diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f97d8fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,293 @@ +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +### Windows template +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + diff --git a/README.rst b/README.rst index ac558c1..186d95d 100644 --- a/README.rst +++ b/README.rst @@ -23,6 +23,5 @@ api_root: http://127.0.0.1:5700/ # GoCQHttp API接口地址/端口 host: 127.0.0.1 # efb-qq-slave 所监听的地址用于接收消息 port: 8000 # 同上 - is_pro: true # 设置为 true 即可 2. 控制台启动 ``ehforwarderbot``, 大功告成! diff --git a/efb_qq_plugin_go_cqhttp/GoCQHttp.py b/efb_qq_plugin_go_cqhttp/GoCQHttp.py index d4163ee..56060e9 100644 --- a/efb_qq_plugin_go_cqhttp/GoCQHttp.py +++ b/efb_qq_plugin_go_cqhttp/GoCQHttp.py @@ -25,12 +25,10 @@ from pkg_resources import resource_filename from requests import RequestException from .ChatMgr import ChatManager -from .Exceptions import CoolQDisconnectedException, CoolQAPIFailureException, CoolQOfflineException, \ - CoolQUnknownException +from .Exceptions import CoolQDisconnectedException, CoolQAPIFailureException, CoolQOfflineException 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_user_avatar, download_group_avatar, upload_image_vim_cn, upload_image_mi, \ - upload_image_sogou, download_file + download_user_avatar, download_group_avatar, download_file class GoCQHttp(BaseClient): @@ -475,13 +473,12 @@ class GoCQHttp(BaseClient): self.logger.debug('[%s] Is edited: %s', msg.uid, msg.edit) if msg.edit: - if self.client_config['is_pro']: - try: - uid_type = msg.uid.split('_') - self.recall_message(uid_type[1]) - except CoolQAPIFailureException: - raise EFBOperationNotSupported(self._("Failed to recall the message!\n" - "This message may have already expired.")) + try: + uid_type = msg.uid.split('_') + self.recall_message(uid_type[1]) + except CoolQAPIFailureException: + raise EFBOperationNotSupported(self._("Failed to recall the message!\n" + "This message may have already expired.")) if msg.type in [MsgType.Text, MsgType.Link]: if msg.text == "kick`": @@ -505,83 +502,26 @@ class GoCQHttp(BaseClient): elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/Sticker/Animation %s", msg.uid, msg.type) text = '' - if not self.client_config['is_pro']: # CoolQ Air - if self.client_config['air_option']['upload_to_smms']: - text = '[Image] {}' - smms_data = None - smms_email = self.client_config['air_option']['smms_email'] - smms_password = self.client_config['air_option']['smms_password'] - try: - smms_data = upload_image_smms(msg.file, msg.path, smms_email, smms_password) - except CoolQUnknownException as e: - text = '[Image]' - self.deliver_alert_to_master(self._('Failed to upload the image to sm.ms! Return Msg: ') - + getattr(e, 'message', repr(e))) - else: - if smms_data is not None: - text = text.format(smms_data['url']) - elif 'upload_to_vim_cn' in self.client_config['air_option'] \ - and self.client_config['air_option']['upload_to_vim_cn']: - text = '[Image] {}' - vim_cn_data = None - try: - vim_cn_data = upload_image_vim_cn(msg.file, msg.path) - except CoolQUnknownException as e: - text = '[Image]' - self.deliver_alert_to_master(self._('Failed to upload the image to vim-cn.com! Return Msg: ') - + getattr(e, 'message', repr(e))) - else: - if vim_cn_data is not None: - text = text.format(vim_cn_data) - elif 'upload_to_mi' in self.client_config['air_option'] \ - and self.client_config['air_option']['upload_to_mi']: - text = '[Image] {}' - mi_data = None - try: - mi_data = upload_image_mi(msg.file, msg.path) - except CoolQUnknownException as e: - text = '[Image]' - self.deliver_alert_to_master(self._('Failed to upload the image to mi.com! Return Msg: ') - + getattr(e, 'message', repr(e))) - else: - if mi_data is not None: - text = text.format(mi_data) - elif 'upload_to_sogou' in self.client_config['air_option'] \ - and self.client_config['air_option']['upload_to_sogou']: - text = '[Image] {}' - sogou_data = None - try: - sogou_data = upload_image_sogou(msg.file, msg.path) - except CoolQUnknownException as e: - text = '[Image]' - self.deliver_alert_to_master(self._('Failed to upload the image to sogou.com! Return Msg: ') - + getattr(e, 'message', repr(e))) - else: - if sogou_data is not None: - text = text.format(sogou_data) - else: - text = '[Image]' + if not self.can_send_image: + self.check_features() # Force checking features + raise EFBOperationNotSupported(self._("Unable to send image now. Please check your CoolQ version " + "or retry later")) + if msg.type != MsgType.Sticker: + text += m.coolq_code_image_wrapper(msg.file, msg.path) else: - if not self.can_send_image: - self.check_features() # Force checking features - raise EFBOperationNotSupported(self._("Unable to send image now. Please check your CoolQ version " - "or retry later")) - if msg.type != MsgType.Sticker: - text += m.coolq_code_image_wrapper(msg.file, msg.path) - else: - with tempfile.NamedTemporaryFile(suffix=".gif") as f: - img = Image.open(msg.file) - try: - alpha = img.split()[3] - mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) - except IndexError: - mask = Image.eval(img.split()[0], lambda a: 0) - img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) - img.paste(255, mask) - img.save(f, transparency=255) - msg.file.close() - f.seek(0) - text += m.coolq_code_image_wrapper(f, f.name) + with tempfile.NamedTemporaryFile(suffix=".gif") as f: + img = Image.open(msg.file) + try: + alpha = img.split()[3] + mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) + except IndexError: + mask = Image.eval(img.split()[0], lambda a: 0) + img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) + img.paste(255, mask) + img.save(f, transparency=255) + msg.file.close() + f.seek(0) + text += m.coolq_code_image_wrapper(f, f.name) msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], text) if msg.text: self.coolq_send_message(chat_type[0], chat_type[1], msg.text) diff --git a/efb_qq_plugin_go_cqhttp/Utils.py b/efb_qq_plugin_go_cqhttp/Utils.py index 181cf6d..2b8a0a2 100644 --- a/efb_qq_plugin_go_cqhttp/Utils.py +++ b/efb_qq_plugin_go_cqhttp/Utils.py @@ -1,17 +1,12 @@ -import json import logging -import ntpath import tempfile import urllib.request from gettext import translation from urllib.error import URLError, HTTPError, ContentTooShortError -import requests from ehforwarderbot import Message, coordinator from pkg_resources import resource_filename -from .Exceptions import CoolQUnknownException - qq_emoji_list = { # created by JogleLew and jqqqqqqqqqq, optimized based on Tim's emoji support 0: '😮', 1: '😣', @@ -629,68 +624,6 @@ def coolq_para_encode(text: str): # Escape special characters for CQ Code param return text -def upload_image_smms(file, path, email, password): # Upload image to sm.ms and return the link - UPLOAD_URL_TOKEN = 'https://sm.ms/api/v2/token' - UPLOAD_URL_IMAGE = 'https://sm.ms/api/v2/upload' - UPLOAD_LOGIN = {'username': email, - 'password': password} - UPLOAD_PARAMS = {'format': 'json', 'ssl': True} - resp = requests.post(UPLOAD_URL_TOKEN, params=UPLOAD_LOGIN) - status = json.loads(resp.text) - if status['code'] == 'success': - token = status['data']['token'] - UPLOAD_HEADER = {'Authorization': token} - else: - logging.getLogger(__name__).warning( - 'WARNING: {}'.format(status['msg'])) - raise CoolQUnknownException(status['msg']) - with open(path, 'rb') as f: - files = {'smfile': f.read()} - resp = requests.post(UPLOAD_URL_IMAGE, files=files, headers=UPLOAD_HEADER, - params=UPLOAD_PARAMS) - status = json.loads(resp.text) - if status['code'] == 'success': - logging.getLogger(__name__).debug('INFO: upload success! url at {}'.format(status['data']['url'])) - return status['data'] - else: - logging.getLogger(__name__).warning('WARNING: {}'.format(status['msg'])) - raise CoolQUnknownException(status['msg']) - - -def upload_image_vim_cn(file, path): # Upload image to img.vim-cn.com and return the link - UPLOAD_URL = 'https://img.vim-cn.com/' - with open(path, 'rb') as f: - files = {'name': f.read()} - resp = requests.post(UPLOAD_URL, files=files) - if resp.status_code != 200: - raise CoolQUnknownException("Failed to upload images to vim-cn.com") - return resp.text - - -def upload_image_sogou(file, path): # Upload image to pic.sogou.com and return the link - UPLOAD_URL = 'https://pic.sogou.com/pic/upload_pic.jsp' - with open(path, 'rb') as f: - files = {'pic_path': f.read()} - resp = requests.post(UPLOAD_URL, files=files) - if resp.status_code != 200: - raise CoolQUnknownException("Failed to upload images to sogou.com") - return "https" + resp.text[4:] # Replace http with https - - -def upload_image_mi(file, path): # Upload image to shopapi.io.mi.com and return the link - UPLOAD_URL = 'https://shopapi.io.mi.com/homemanage/shop/uploadpic' - with open(path, 'rb') as f: - files = {'pic': (ntpath.basename(path), f.read(), "image/jpeg")} - resp = requests.post(UPLOAD_URL, files=files) - if resp.status_code != 200: - raise CoolQUnknownException("Failed to upload images to mi.com") - status = json.loads(resp.text) - print(status) - if status['message'] != "ok": - raise CoolQUnknownException("Failed to upload images to mi.com") - return status['result'] - - def param_spliter(str_param): params = str_param.split(";") param = {}