Support go-cqhttp

This commit is contained in:
XYenon 2021-05-31 01:16:50 +08:00
parent da15b9bae4
commit 54c1cbbaaa
9 changed files with 30 additions and 215 deletions

View File

@ -1,3 +0,0 @@
# coding: utf-8
__version__ = '2.0.0a0'

View File

@ -1,4 +1,3 @@
# coding: utf-8
import contextlib
import logging
@ -10,7 +9,6 @@ from efb_qq_slave import QQMessengerChannel
class ChatManager:
def __init__(self, channel: 'QQMessengerChannel'):
self.channel: 'QQMessengerChannel' = channel
self.logger: logging.Logger = logging.getLogger(__name__)
@ -27,49 +25,6 @@ class ChatManager:
name="Chat Missing"
)
"""
def build_efb_chat_as_user(self, uid, is_chat, in_group=None, is_discuss=False):
efb_chat = EFBChat(self.channel)
efb_chat.chat_uid = 'user' + str(uid)
i: dict = self.channel.QQClient.get_stranger_info(uid)
efb_chat.chat_name = i['nickname']
efb_chat.chat_alias = None
efb_chat.chat_type = ChatType.User
efb_chat.is_chat = is_chat
efb_chat.vendor_specific = {'is_anonymous': False}
if in_group is not None:
efb_chat.group = self.build_efb_chat_as_group(in_group, is_discuss)
return efb_chat
def build_efb_chat_as_group(self, uid, discuss=False):
efb_chat = EFBChat(self.channel)
if not discuss:
efb_chat.chat_uid = 'group' + str(uid)
i = self.channel.QQClient.get_group_info(uid)
efb_chat.chat_name = i['group_name']
efb_chat.chat_type = ChatType.Group
efb_chat.vendor_specific = {'is_discuss': False}
# todo Add user to efb_chat.member
else:
efb_chat.chat_uid = 'discuss' + str(uid)
efb_chat.chat_name = 'Discuss Group' # todo Find a way to distinguish from different discuss group
efb_chat.chat_type = ChatType.Group
efb_chat.vendor_specific = {'is_discuss': True}
return efb_chat
def build_efb_chat_as_anonymous_user(self, nickname, flag, anonymous_id, group_id, is_discuss):
efb_chat = EFBChat(self.channel)
efb_chat.chat_uid = flag
efb_chat.chat_name = nickname
efb_chat.chat_type = ChatType.User
efb_chat.is_chat = False
efb_chat.vendor_specific = {'is_anonymous': True,
'anonymous_id': anonymous_id}
efb_chat.group = self.build_efb_chat_as_group(group_id, is_discuss)
return efb_chat
"""
def build_efb_chat_as_private(self, context):
uid = context['user_id']
if 'sender' not in context or 'nickname' not in context['sender']:

View File

@ -1,4 +1,3 @@
# coding: utf-8
import logging
import tempfile
import threading
@ -30,8 +29,8 @@ from .Exceptions import CoolQDisconnectedException, CoolQAPIFailureException, Co
CoolQUnknownException
from .MsgDecorator import QQMsgProcessor
from .Utils import qq_emoji_list, async_send_messages_to_master, process_quote_text, coolq_text_encode, \
upload_image_smms, download_file_from_qzone, download_user_avatar, download_group_avatar, \
get_friend_group_via_qq_show, upload_image_vim_cn, upload_image_mi, upload_image_sogou, get_stranger_info_via_qzone
upload_image_smms, download_user_avatar, download_group_avatar, upload_image_vim_cn, upload_image_mi, \
upload_image_sogou, download_file
class CoolQ(BaseClient):
@ -257,18 +256,11 @@ class CoolQ(BaseClient):
context['message'] = text
self.send_efb_group_notice(context)
cred = self.coolq_api_query('get_credentials')
cookies = cred['cookies']
csrf_token = cred['csrf_token']
param_dict = {
'context': context,
'cookie': cookies,
'csrf_token': csrf_token,
'uin': self.get_qq_uid(),
'group_id': context['group_id'],
'file_id': context['file']['id'],
'filename': context['file']['name'],
'file_size': context['file']['size']
'busid': context['file']['busid']
}
threading.Thread(target=self.async_download_file, args=[], kwargs=param_dict).start()
@ -404,9 +396,7 @@ class CoolQ(BaseClient):
return 'Done'
def get_stranger_info(self, user_id):
return get_stranger_info_via_qzone(user_id)
# return self.coolq_api_query('get_stranger_info', user_id=user_id, no_cache=False)
# return self.coolq_bot.get_stranger_info(user_id=user_id, no_cache=False)
return self.coolq_api_query('get_stranger_info', user_id=user_id)
def get_login_info(self) -> Dict[Any, Any]:
res = self.coolq_bot.get_status()
@ -450,41 +440,18 @@ class CoolQ(BaseClient):
self.deliver_alert_to_master(self._('Failed to retrieve the friend list.\n'
'Only groups are shown.'))
return []
res = self.friend_list
users = []
for i in range(len(res)): # friend group
current_user = res[i]
txt = ''
if str(current_user['user_id']) in self.friend_group:
txt = '[{}] {}'
txt = txt.format(self.friend_group[str(current_user['user_id'])], current_user['nickname'])
for current_user in self.friend_list: # friend group
if current_user['user_id'] in self.friend_group:
txt = '[{}] {}'.format(self.friend_group[current_user['user_id']], current_user['nickname'])
else:
txt = '{}'
txt = txt.format(current_user['nickname'])
txt = '{}'.format(current_user['nickname'])
# Disable nickname & remark comparison for it's too time-consuming
context = {'user_id': str(current_user['user_id']),
'nickname': txt,
'alias': current_user['remark']}
efb_chat = self.chat_manager.build_efb_chat_as_private(context)
# efb_chat = self.chat_manager.build_efb_chat_as_user(context, True)
users.append(efb_chat)
'''
for i in range(len(res)): # friend group
for j in range(len(res[i]['friends'])):
current_user = res[i]['friends'][j]
txt = '[{}] {}'
txt = txt.format(res[i]['friend_group_name'], current_user['remark'])
if current_user['nickname'] == current_user['remark']: # no remark name
context = {'user_id': str(current_user['user_id']),
'nickname': txt,
'alias': None}
else:
context = {'user_id': str(current_user['user_id']),
'nickname': current_user['nickname'],
'alias': txt}
efb_chat = self.chat_manager.build_efb_chat_as_user(context, True)
users.append(efb_chat)
'''
return users
def receive_message(self):
@ -778,31 +745,15 @@ class CoolQ(BaseClient):
def update_friend_group(self):
# Mirai doesn't support retrieving friend group, neither does get_credentials unfortunately
return {}
# Warning: Experimental API
try:
# res = self.coolq_api_query('_get_friend_list')
# relationship = {}
# if res:
# for group in res:
# for friend in group['friends']:
# relationship[str(friend['user_id'])] = str(group['friend_group_name'])
# self.friend_group = relationship
# Use QShow API
cred = self.coolq_api_query('get_credentials')
cookies = cred['cookies']
csrf_token = cred['csrf_token']
self.friend_group = get_friend_group_via_qq_show(cookies, csrf_token)
except Exception as e:
self.logger.warning('Failed to update friend group' + str(e))
def update_friend_list(self):
self.friend_list = self.coolq_api_query('get_friend_list')
if self.friend_list:
self.logger.debug('Update friend list completed. Entries: %s', len(self.friend_list))
for friend in self.friend_list:
if(friend['remark']==''):
if friend['remark'] == '':
friend['remark'] = friend['nickname']
self.friend_remark[str(friend['user_id'])] = {
self.friend_remark[friend['user_id']] = {
'nickname': friend['nickname'],
'remark': friend['remark']
}
@ -839,44 +790,16 @@ class CoolQ(BaseClient):
self.update_contacts_timer.start()
def get_friend_remark(self, uid):
if not self.friend_list:
if (not self.friend_list) or (uid not in self.friend_remark):
try:
self.update_friend_list()
except CoolQAPIFailureException:
# self.deliver_alert_to_master(self._('Failed to update friend remark name'))
self.logger.exception(self._('Failed to update friend remark name'))
return ''
# if not self.friend_group:
# try:
# self.update_friend_group()
# except CoolQAPIFailureException:
# self.deliver_alert_to_master(self._('Failed to get friend groups'))
# self.logger.exception(self._('Failed to get friend groups'))
# return ''
if str(uid) not in self.friend_remark:
if uid not in self.friend_remark:
return None # I don't think you have such a friend
return self.friend_remark[str(uid)]['remark']
'''
for i in range(len(self.friend_list)): # friend group
for j in range(len(self.friend_list[i]['friend'])):
current_user = self.friend_list[i]['friend'][j]
if current_user['uin'] != str(uid):
continue
return current_user['name']
'''
'''
for i in range(len(self.friend_list)): # friend group
for j in range(len(self.friend_list[i]['friends'])):
current_user = self.friend_list[i]['friends'][j]
if current_user['user_id'] != uid:
continue
if current_user['nickname'] == current_user['remark'] or current_user['nickname'] == '':
# no remark name
return current_user['nickname']
else:
return current_user['remark']
return None # I don't think you've got such a friend
'''
return self.friend_remark[uid]['remark']
def send_efb_group_notice(self, context):
context['message_type'] = 'group'
@ -978,8 +901,13 @@ class CoolQ(BaseClient):
+ getattr(e, 'message', repr(e)))
return 'Done'
def async_download_file(self, context, **kwargs):
res = download_file_from_qzone(**kwargs)
def async_download_file(self, context, group_id, file_id, busid):
file = self.coolq_api_query('get_group_file_url',
group_id=group_id,
file_id=file_id,
busid=busid)
download_url = file['url']
res = download_file(download_url)
if isinstance(res, str):
context['message'] = self._("[Download] ") + res
self.send_efb_group_notice(context)

View File

@ -1,5 +1,3 @@
# coding: utf-8
import base64
import html
import json

View File

@ -1,14 +1,10 @@
# coding: utf-8
import re
import json
import logging
import ntpath
import tempfile
import urllib.request
from gettext import translation
from typing import *
from urllib.error import URLError, HTTPError, ContentTooShortError
from urllib.parse import quote
import requests
from ehforwarderbot import Message, coordinator
@ -704,21 +700,10 @@ def param_spliter(str_param):
return param
def download_file_from_qzone(cookie: str, csrf_token: str, uin, group_id, file_id, filename, file_size):
cookie_arr = param_spliter(cookie)
url = "http://qun.qzone.qq.com/cgi-bin/group_share_get_downurl?uin=" + str(uin) + "&pa=/104/" + \
str(file_id) + "&groupid=" + str(group_id) + "&bussinessid=0&charset=utf-8&g_tk=" + str(csrf_token) + "&r=888"
ret = requests.get(url, cookies=cookie_arr)
data = json.loads(ret.text.split("(")[1].split(")")[0])['data']
cookie += "; FTN5K=" + str(data['cookie'])
download_url = data['url']
download_url += "/" + quote(filename)
if file_size >= 50*1024*1024: # File size is bigger than 50MiB
return _("File is too big to be downloaded")
def download_file(download_url):
file = tempfile.NamedTemporaryFile()
try:
opener = urllib.request.build_opener()
opener.addheaders.append(('Cookie', cookie))
urllib.request.install_opener(opener)
urllib.request.urlretrieve(download_url, file.name)
except (URLError, HTTPError, ContentTooShortError) as e:
@ -729,20 +714,6 @@ def download_file_from_qzone(cookie: str, csrf_token: str, uin, group_id, file_i
raise EOFError('File downloaded is Empty')
file.seek(0)
return file
'''
try:
opener = urllib.request.build_opener()
opener.addheaders.append(('Cookie', cookie))
with opener.open(download_url) as response, tempfile.NamedTemporaryFile() as f:
shutil.copyfileobj(response, f)
if f.seek(0, 2) <= 0:
raise EOFError('File downloaded is Empty')
f.seek(0)
return f
except Exception as e:
logging.getLogger(__name__).warning("Error occurs when downloading files" + str(e))
return url
'''
def download_user_avatar(uid: str):
@ -777,22 +748,6 @@ def download_group_avatar(uid: str):
return file
def get_friend_group_via_qq_show(cookie: str, csrf_token: str) -> Dict[str, str]:
# This function won't check before execute, instead all the exceptions will be thrown
cookie_arr = param_spliter(cookie)
url = "https://show.qq.com/cgi-bin/qqshow_user_friendgroup?g_tk={csrf_token}&omode=4" \
.format(csrf_token=csrf_token)
ret = requests.get(url, cookies=cookie_arr)
data = json.loads(ret.text)
friend_group = {}
for i in range(len(data['data']['group'])): # friend group
for j in range(len(data['data']['group'][i]['friend'])):
current_user = str(data['data']['group'][i]['friend'][j]['uin'])
current_group = data['data']['group'][i]['name']
friend_group[current_user] = current_group
return friend_group
def download_voice(filename: str, api_root: str, access_token: str):
file = tempfile.NamedTemporaryFile()
url = '{url}/data/record/{file}'.format(url=api_root, file=filename)
@ -809,22 +764,3 @@ def download_voice(filename: str, api_root: str, access_token: str):
raise EOFError('File downloaded is Empty')
file.seek(0)
return file
def get_stranger_info_via_qzone(uin: str):
pattern = re.compile(r"\((.*)\)")
resp = requests.get("https://users.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins={id}".format(id=uin))
# Assume that this API is always available
data = pattern.findall(resp.text)
if not data:
return ""
try:
data = json.loads(data[0])
ret = {
"uin": uin,
"nickname": data[uin][6],
"avatar_url": data[uin][0]
}
return ret
except:
return ""

View File

@ -0,0 +1 @@
__version__ = '2.0.1'

View File

@ -5,24 +5,24 @@ if sys.version_info < (3, 6):
raise Exception("Python 3.6 or higher is required. Your version is %s." % sys.version)
__version__ = ""
exec(open('efb_qq_plugin_coolq/__version__.py').read())
exec(open('efb_qq_plugin_go_cqhttp/__version__.py').read())
long_description = open('README.rst').read()
setup(
name='efb-qq-plugin-coolq',
name='efb-qq-plugin-go-cqhttp',
packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
version=__version__,
description='EQS plugin for CoolQ API Compatible Client.',
description='EQS plugin for Go-CQHttp API Compatible Client.',
long_description=long_description,
include_package_data=True,
author='Milkice',
author_email='milkice@milkice.me',
url='https://github.com/milkice233/efb-qq-plugin-coolq',
author='XYenon',
author_email='i@xyenon.bid',
url='https://github.com/XYenon/efb-qq-plugin-go-cqhttp',
license='GPLv3',
python_requires='>=3.6',
keywords=['ehforwarderbot', 'EH Forwarder Bot', 'EH Forwarder Bot Slave Channel',
'qq', 'chatbot', 'EQS', 'CoolQ'],
'qq', 'chatbot', 'EQS', 'CoolQ', 'go-cqhttp'],
classifiers=[
"Development Status :: 3 - Alpha",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
@ -40,6 +40,6 @@ setup(
'requests', 'python-magic', 'Pillow', 'cqhttp>=1.3.0', 'cherrypy>=18.5.0'
],
entry_points={
'ehforwarderbot.qq.plugin': 'CoolQ = efb_qq_plugin_coolq:CoolQ'
'ehforwarderbot.qq.plugin': 'CoolQ = efb_qq_plugin_go_cqhttp:CoolQ'
}
)