From fa4dc1dcbf0910a1f371b1058774bcfd50f2c980 Mon Sep 17 00:00:00 2001 From: LittleCoder Date: Wed, 7 Dec 2016 20:04:30 +0800 Subject: [PATCH] Update file uploading protocol --- .gitignore | 1 + docs/index.md | 2 +- itchat/components/contact.py | 2 +- itchat/components/messages.py | 48 +++++++++++++++++++++++++---------- itchat/config.py | 2 +- itchat/core.py | 3 ++- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index abdb8c7f..1f0a52be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build/* dist/* +test/* itchat.egg-info/* *.pyc *.swp diff --git a/docs/index.md b/docs/index.md index f4778020..58ed4ef5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # itchat -[![Gitter][gitter-picture]][gitter] ![py27][py27] ![py35][py35] [English version][english-version] +[![Gitter][gitter-picture]][gitter] ![py27][py27] ![py35][py35] itchat是一个开源的微信个人号接口,使用python调用微信从未如此简单。 diff --git a/itchat/components/contact.py b/itchat/components/contact.py index ec56f7dd..c44cbb00 100644 --- a/itchat/components/contact.py +++ b/itchat/components/contact.py @@ -1,4 +1,4 @@ -import os, time, re +import os, time, re, io import json, copy import traceback, logging diff --git a/itchat/components/messages.py b/itchat/components/messages.py index 9823fcaf..8b106a9e 100644 --- a/itchat/components/messages.py +++ b/itchat/components/messages.py @@ -1,6 +1,6 @@ import os, time, re, io import json -import mimetypes +import mimetypes, hashlib import traceback, logging import requests @@ -235,39 +235,59 @@ def send_msg(self, msg='Test Message', toUserName=None): r = self.send_raw_msg(1, msg, toUserName) return r -def upload_file(self, fileDir, isPicture=False, isVideo=False): +def upload_file(self, fileDir, isPicture=False, isVideo=False, + toUserName='filehelper'): logger.debug('Request to upload a %s: %s' % ( 'picture' if isPicture else 'video' if isVideo else 'file', fileDir)) if not utils.check_file(fileDir): return ReturnValue({'BaseResponse': { 'ErrMsg': 'No file found in specific dir', 'Ret': -1002, }}) - url = self.loginInfo.get('fileUrl', self.loginInfo['url']) + \ + fileSize = os.path.getsize(fileDir) + fileSymbol = 'pic' if isPicture else 'video' if isVideo else'doc' + with open(fileDir, 'rb') as f: fileMd5 = hashlib.md5(f.read()).hexdigest() + file = open(fileDir, 'rb') + chunks = int(fileSize / 524288) + 1 + for chunk in range(chunks): + r = upload_chunk_file(self, fileDir, fileSymbol, fileSize, + fileMd5, file, toUserName, chunk, chunks) + file.close() + self.loginInfo['msgid'] += 1 + return ReturnValue(rawResponse=r) + +def upload_chunk_file(core, fileDir, fileSymbol, fileSize, + fileMd5, file, toUserName, chunk, chunks): + url = core.loginInfo.get('fileUrl', core.loginInfo['url']) + \ '/webwxuploadmedia?f=json' # save it on server - fileSize = str(os.path.getsize(fileDir)) - cookiesList = {name:data for name,data in self.s.cookies.items()} + cookiesList = {name:data for name,data in core.s.cookies.items()} fileType = mimetypes.guess_type(fileDir)[0] or 'application/octet-stream' files = { 'id': (None, 'WU_FILE_0'), 'name': (None, os.path.basename(fileDir)), 'type': (None, fileType), 'lastModifiedDate': (None, time.strftime('%a %b %d %Y %H:%M:%S GMT+0800 (CST)')), - 'size': (None, fileSize), - 'mediatype': (None, 'pic' if isPicture else 'video' if isVideo else'doc'), + 'size': (None, str(fileSize)), + 'mediatype': (None, fileSymbol), 'uploadmediarequest': (None, json.dumps({ - 'BaseRequest': self.loginInfo['BaseRequest'], - 'ClientMediaId': int(time.time()), + 'UploadType': (None, 2), + 'BaseRequest': core.loginInfo['BaseRequest'], + 'ClientMediaId': core.loginInfo['msgid'], 'TotalLen': fileSize, 'StartPos': 0, 'DataLen': fileSize, - 'MediaType': 4, }, separators = (',', ':'))), + 'MediaType': 4, + 'FromUserName': core.storageClass.userName, + 'ToUserName': toUserName, + 'FileMd5': fileMd5, + }, separators = (',', ':'))), 'webwx_data_ticket': (None, cookiesList['webwx_data_ticket']), - 'pass_ticket': (None, 'undefined'), - 'filename' : (os.path.basename(fileDir), open(fileDir, 'rb'), fileType), } + 'pass_ticket': (None, core.loginInfo['pass_ticket']), + 'filename' : (os.path.basename(fileDir), file.read(524288), fileType), } + if chunks != 1: + files['chunk'], files['chunks'] = (None, str(chunk)), (None, str(chunks)) headers = { 'User-Agent' : config.USER_AGENT } - r = self.s.post(url, files=files, headers=headers) - return ReturnValue(rawResponse=r) + return core.s.post(url, files=files, headers=headers) def send_file(self, fileDir, toUserName=None, mediaId=None): logger.debug('Request to send a file(mediaId: %s) to %s: %s' % ( diff --git a/itchat/config.py b/itchat/config.py index 2736cd0a..e544fb7a 100644 --- a/itchat/config.py +++ b/itchat/config.py @@ -1,6 +1,6 @@ import os, platform -VERSION = '1.2.11' +VERSION = '1.2.12' BASE_URL = 'https://login.weixin.qq.com' OS = platform.system() #Windows, Linux, Darwin DIR = os.getcwd() diff --git a/itchat/core.py b/itchat/core.py index f3c8a36d..44ee1e79 100644 --- a/itchat/core.py +++ b/itchat/core.py @@ -311,7 +311,8 @@ def send_msg(self, msg='Test Message', toUserName=None): it is defined in components/messages.py ''' raise NotImplementedError() - def upload_file(self, fileDir, isPicture=False, isVideo=False): + def upload_file(self, fileDir, isPicture=False, isVideo=False, + toUserName='filehelper'): ''' upload file to server and get mediaId for options - fileDir: dir for file ready for upload