457 lines
20KB

  1. import requests
  2. from . import storage
  3. class Core(object):
  4. def __init__(self):
  5. ''' init is the only method defined in core.py
  6. alive is value showing whether core is running
  7. - you should call logout method to change it
  8. - after logout, a core object can login again
  9. storageClass only uses basic python types
  10. - so for advanced uses, inherit it yourself
  11. receivingRetryCount is for receiving loop retry
  12. - it's 5 now, but actually even 1 is enough
  13. - failing is failing
  14. '''
  15. self.alive, self.isLogging = False, False
  16. self.storageClass = storage.Storage(self)
  17. self.memberList = self.storageClass.memberList
  18. self.mpList = self.storageClass.mpList
  19. self.chatroomList = self.storageClass.chatroomList
  20. self.msgList = self.storageClass.msgList
  21. self.loginInfo = {}
  22. self.s = requests.Session()
  23. self.uuid = None
  24. self.functionDict = {'FriendChat': {}, 'GroupChat': {}, 'MpChat': {}}
  25. self.useHotReload, self.hotReloadDir = False, 'itchat.pkl'
  26. self.receivingRetryCount = 5
  27. def login(self, enableCmdQR=False, picDir=None, qrCallback=None,
  28. loginCallback=None, exitCallback=None):
  29. ''' log in like web wechat does
  30. for log in
  31. - a QR code will be downloaded and opened
  32. - then scanning status is logged, it paused for you confirm
  33. - finally it logged in and show your nickName
  34. for options
  35. - enableCmdQR: show qrcode in command line
  36. - integers can be used to fit strange char length
  37. - picDir: place for storing qrcode
  38. - qrCallback: method that should accept uuid, status, qrcode
  39. - loginCallback: callback after successfully logged in
  40. - if not set, screen is cleared and qrcode is deleted
  41. - exitCallback: callback after logged out
  42. - it contains calling of logout
  43. for usage
  44. ..code::python
  45. import itchat
  46. itchat.login()
  47. it is defined in components/login.py
  48. and of course every single move in login can be called outside
  49. - you may scan source code to see how
  50. - and modified according to your own demand
  51. '''
  52. raise NotImplementedError()
  53. def get_QRuuid(self):
  54. ''' get uuid for qrcode
  55. uuid is the symbol of qrcode
  56. - for logging in, you need to get a uuid first
  57. - for downloading qrcode, you need to pass uuid to it
  58. - for checking login status, uuid is also required
  59. if uuid has timed out, just get another
  60. it is defined in components/login.py
  61. '''
  62. raise NotImplementedError()
  63. def get_QR(self, uuid=None, enableCmdQR=False, picDir=None, qrCallback=None):
  64. ''' download and show qrcode
  65. for options
  66. - uuid: if uuid is not set, latest uuid you fetched will be used
  67. - enableCmdQR: show qrcode in cmd
  68. - picDir: where to store qrcode
  69. - qrCallback: method that should accept uuid, status, qrcode
  70. it is defined in components/login.py
  71. '''
  72. raise NotImplementedError()
  73. def check_login(self, uuid=None):
  74. ''' check login status
  75. for options:
  76. - uuid: if uuid is not set, latest uuid you fetched will be used
  77. for return values:
  78. - a string will be returned
  79. - for meaning of return values
  80. - 200: log in successfully
  81. - 201: waiting for press confirm
  82. - 408: uuid timed out
  83. - 0 : unknown error
  84. for processing:
  85. - syncUrl and fileUrl is set
  86. - BaseRequest is set
  87. blocks until reaches any of above status
  88. it is defined in components/login.py
  89. '''
  90. raise NotImplementedError()
  91. def web_init(self):
  92. ''' get info necessary for initializing
  93. for processing:
  94. - own account info is set
  95. - inviteStartCount is set
  96. - syncKey is set
  97. - part of contact is fetched
  98. it is defined in components/login.py
  99. '''
  100. raise NotImplementedError()
  101. def show_mobile_login(self):
  102. ''' show web wechat login sign
  103. the sign is on the top of mobile phone wechat
  104. sign will be added after sometime even without calling this function
  105. it is defined in components/login.py
  106. '''
  107. raise NotImplementedError()
  108. def start_receiving(self, exitCallback=None, getReceivingFnOnly=False):
  109. ''' open a thread for heart loop and receiving messages
  110. for options:
  111. - exitCallback: callback after logged out
  112. - it contains calling of logout
  113. - getReceivingFnOnly: if True thread will not be created and started. Instead, receive fn will be returned.
  114. for processing:
  115. - messages: msgs are formatted and passed on to registered fns
  116. - contact : chatrooms are updated when related info is received
  117. it is defined in components/login.py
  118. '''
  119. raise NotImplementedError()
  120. def get_msg(self):
  121. ''' fetch messages
  122. for fetching
  123. - method blocks for sometime until
  124. - new messages are to be received
  125. - or anytime they like
  126. - synckey is updated with returned synccheckkey
  127. it is defined in components/login.py
  128. '''
  129. raise NotImplementedError()
  130. def logout(self):
  131. ''' logout
  132. if core is now alive
  133. logout will tell wechat backstage to logout
  134. and core gets ready for another login
  135. it is defined in components/login.py
  136. '''
  137. raise NotImplementedError()
  138. def update_chatroom(self, userName, detailedMember=False):
  139. ''' update chatroom
  140. for chatroom contact
  141. - a chatroom contact need updating to be detailed
  142. - detailed means members, encryid, etc
  143. - auto updating of heart loop is a more detailed updating
  144. - member uin will also be filled
  145. - once called, updated info will be stored
  146. for options
  147. - userName: 'UserName' key of chatroom or a list of it
  148. - detailedMember: whether to get members of contact
  149. it is defined in components/contact.py
  150. '''
  151. raise NotImplementedError()
  152. def update_friend(self, userName):
  153. ''' update chatroom
  154. for friend contact
  155. - once called, updated info will be stored
  156. for options
  157. - userName: 'UserName' key of a friend or a list of it
  158. it is defined in components/contact.py
  159. '''
  160. raise NotImplementedError()
  161. def get_contact(self, update=False):
  162. ''' fetch part of contact
  163. for part
  164. - all the massive platforms and friends are fetched
  165. - if update, only starred chatrooms are fetched
  166. for options
  167. - update: if not set, local value will be returned
  168. for results
  169. - chatroomList will be returned
  170. it is defined in components/contact.py
  171. '''
  172. raise NotImplementedError()
  173. def get_friends(self, update=False):
  174. ''' fetch friends list
  175. for options
  176. - update: if not set, local value will be returned
  177. for results
  178. - a list of friends' info dicts will be returned
  179. it is defined in components/contact.py
  180. '''
  181. raise NotImplementedError()
  182. def get_chatrooms(self, update=False, contactOnly=False):
  183. ''' fetch chatrooms list
  184. for options
  185. - update: if not set, local value will be returned
  186. - contactOnly: if set, only starred chatrooms will be returned
  187. for results
  188. - a list of chatrooms' info dicts will be returned
  189. it is defined in components/contact.py
  190. '''
  191. raise NotImplementedError()
  192. def get_mps(self, update=False):
  193. ''' fetch massive platforms list
  194. for options
  195. - update: if not set, local value will be returned
  196. for results
  197. - a list of platforms' info dicts will be returned
  198. it is defined in components/contact.py
  199. '''
  200. raise NotImplementedError()
  201. def set_alias(self, userName, alias):
  202. ''' set alias for a friend
  203. for options
  204. - userName: 'UserName' key of info dict
  205. - alias: new alias
  206. it is defined in components/contact.py
  207. '''
  208. raise NotImplementedError()
  209. def set_pinned(self, userName, isPinned=True):
  210. ''' set pinned for a friend or a chatroom
  211. for options
  212. - userName: 'UserName' key of info dict
  213. - isPinned: whether to pin
  214. it is defined in components/contact.py
  215. '''
  216. raise NotImplementedError()
  217. def accept_friend(self, userName, v4,autoUpdate=True):
  218. ''' accept a friend or accept a friend
  219. for options
  220. - userName: 'UserName' for friend's info dict
  221. - status:
  222. - for adding status should be 2
  223. - for accepting status should be 3
  224. - ticket: greeting message
  225. - userInfo: friend's other info for adding into local storage
  226. it is defined in components/contact.py
  227. '''
  228. raise NotImplementedError()
  229. def get_head_img(self, userName=None, chatroomUserName=None, picDir=None):
  230. ''' place for docs
  231. for options
  232. - if you want to get chatroom header: only set chatroomUserName
  233. - if you want to get friend header: only set userName
  234. - if you want to get chatroom member header: set both
  235. it is defined in components/contact.py
  236. '''
  237. raise NotImplementedError()
  238. def create_chatroom(self, memberList, topic=''):
  239. ''' create a chatroom
  240. for creating
  241. - its calling frequency is strictly limited
  242. for options
  243. - memberList: list of member info dict
  244. - topic: topic of new chatroom
  245. it is defined in components/contact.py
  246. '''
  247. raise NotImplementedError()
  248. def set_chatroom_name(self, chatroomUserName, name):
  249. ''' set chatroom name
  250. for setting
  251. - it makes an updating of chatroom
  252. - which means detailed info will be returned in heart loop
  253. for options
  254. - chatroomUserName: 'UserName' key of chatroom info dict
  255. - name: new chatroom name
  256. it is defined in components/contact.py
  257. '''
  258. raise NotImplementedError()
  259. def delete_member_from_chatroom(self, chatroomUserName, memberList):
  260. ''' deletes members from chatroom
  261. for deleting
  262. - you can't delete yourself
  263. - if so, no one will be deleted
  264. - strict-limited frequency
  265. for options
  266. - chatroomUserName: 'UserName' key of chatroom info dict
  267. - memberList: list of members' info dict
  268. it is defined in components/contact.py
  269. '''
  270. raise NotImplementedError()
  271. def add_member_into_chatroom(self, chatroomUserName, memberList,
  272. useInvitation=False):
  273. ''' add members into chatroom
  274. for adding
  275. - you can't add yourself or member already in chatroom
  276. - if so, no one will be added
  277. - if member will over 40 after adding, invitation must be used
  278. - strict-limited frequency
  279. for options
  280. - chatroomUserName: 'UserName' key of chatroom info dict
  281. - memberList: list of members' info dict
  282. - useInvitation: if invitation is not required, set this to use
  283. it is defined in components/contact.py
  284. '''
  285. raise NotImplementedError()
  286. def send_raw_msg(self, msgType, content, toUserName):
  287. ''' many messages are sent in a common way
  288. for demo
  289. .. code:: python
  290. @itchat.msg_register(itchat.content.CARD)
  291. def reply(msg):
  292. itchat.send_raw_msg(msg['MsgType'], msg['Content'], msg['FromUserName'])
  293. there are some little tricks here, you may discover them yourself
  294. but remember they are tricks
  295. it is defined in components/messages.py
  296. '''
  297. raise NotImplementedError()
  298. def send_msg(self, msg='Test Message', toUserName=None):
  299. ''' send plain text message
  300. for options
  301. - msg: should be unicode if there's non-ascii words in msg
  302. - toUserName: 'UserName' key of friend dict
  303. it is defined in components/messages.py
  304. '''
  305. raise NotImplementedError()
  306. def upload_file(self, fileDir, isPicture=False, isVideo=False,
  307. toUserName='filehelper', file_=None, preparedFile=None):
  308. ''' upload file to server and get mediaId
  309. for options
  310. - fileDir: dir for file ready for upload
  311. - isPicture: whether file is a picture
  312. - isVideo: whether file is a video
  313. for return values
  314. will return a ReturnValue
  315. if succeeded, mediaId is in r['MediaId']
  316. it is defined in components/messages.py
  317. '''
  318. raise NotImplementedError()
  319. def send_file(self, fileDir, toUserName=None, mediaId=None, file_=None):
  320. ''' send attachment
  321. for options
  322. - fileDir: dir for file ready for upload
  323. - mediaId: mediaId for file.
  324. - if set, file will not be uploaded twice
  325. - toUserName: 'UserName' key of friend dict
  326. it is defined in components/messages.py
  327. '''
  328. raise NotImplementedError()
  329. def send_image(self, fileDir=None, toUserName=None, mediaId=None, file_=None):
  330. ''' send image
  331. for options
  332. - fileDir: dir for file ready for upload
  333. - if it's a gif, name it like 'xx.gif'
  334. - mediaId: mediaId for file.
  335. - if set, file will not be uploaded twice
  336. - toUserName: 'UserName' key of friend dict
  337. it is defined in components/messages.py
  338. '''
  339. raise NotImplementedError()
  340. def send_video(self, fileDir=None, toUserName=None, mediaId=None, file_=None):
  341. ''' send video
  342. for options
  343. - fileDir: dir for file ready for upload
  344. - if mediaId is set, it's unnecessary to set fileDir
  345. - mediaId: mediaId for file.
  346. - if set, file will not be uploaded twice
  347. - toUserName: 'UserName' key of friend dict
  348. it is defined in components/messages.py
  349. '''
  350. raise NotImplementedError()
  351. def send(self, msg, toUserName=None, mediaId=None):
  352. ''' wrapped function for all the sending functions
  353. for options
  354. - msg: message starts with different string indicates different type
  355. - list of type string: ['@fil@', '@img@', '@msg@', '@vid@']
  356. - they are for file, image, plain text, video
  357. - if none of them matches, it will be sent like plain text
  358. - toUserName: 'UserName' key of friend dict
  359. - mediaId: if set, uploading will not be repeated
  360. it is defined in components/messages.py
  361. '''
  362. raise NotImplementedError()
  363. def revoke(self, msgId, toUserName, localId=None):
  364. ''' revoke message with its and msgId
  365. for options
  366. - msgId: message Id on server
  367. - toUserName: 'UserName' key of friend dict
  368. - localId: message Id at local (optional)
  369. it is defined in components/messages.py
  370. '''
  371. raise NotImplementedError()
  372. def dump_login_status(self, fileDir=None):
  373. ''' dump login status to a specific file
  374. for option
  375. - fileDir: dir for dumping login status
  376. it is defined in components/hotreload.py
  377. '''
  378. raise NotImplementedError()
  379. def load_login_status(self, fileDir,
  380. loginCallback=None, exitCallback=None):
  381. ''' load login status from a specific file
  382. for option
  383. - fileDir: file for loading login status
  384. - loginCallback: callback after successfully logged in
  385. - if not set, screen is cleared and qrcode is deleted
  386. - exitCallback: callback after logged out
  387. - it contains calling of logout
  388. it is defined in components/hotreload.py
  389. '''
  390. raise NotImplementedError()
  391. def auto_login(self, hotReload=False, statusStorageDir='itchat.pkl',
  392. enableCmdQR=False, picDir=None, qrCallback=None,
  393. loginCallback=None, exitCallback=None):
  394. ''' log in like web wechat does
  395. for log in
  396. - a QR code will be downloaded and opened
  397. - then scanning status is logged, it paused for you confirm
  398. - finally it logged in and show your nickName
  399. for options
  400. - hotReload: enable hot reload
  401. - statusStorageDir: dir for storing log in status
  402. - enableCmdQR: show qrcode in command line
  403. - integers can be used to fit strange char length
  404. - picDir: place for storing qrcode
  405. - loginCallback: callback after successfully logged in
  406. - if not set, screen is cleared and qrcode is deleted
  407. - exitCallback: callback after logged out
  408. - it contains calling of logout
  409. - qrCallback: method that should accept uuid, status, qrcode
  410. for usage
  411. ..code::python
  412. import itchat
  413. itchat.auto_login()
  414. it is defined in components/register.py
  415. and of course every single move in login can be called outside
  416. - you may scan source code to see how
  417. - and modified according to your own demond
  418. '''
  419. raise NotImplementedError()
  420. def configured_reply(self):
  421. ''' determine the type of message and reply if its method is defined
  422. however, I use a strange way to determine whether a msg is from massive platform
  423. I haven't found a better solution here
  424. The main problem I'm worrying about is the mismatching of new friends added on phone
  425. If you have any good idea, pleeeease report an issue. I will be more than grateful.
  426. '''
  427. raise NotImplementedError()
  428. def msg_register(self, msgType,
  429. isFriendChat=False, isGroupChat=False, isMpChat=False):
  430. ''' a decorator constructor
  431. return a specific decorator based on information given
  432. '''
  433. raise NotImplementedError()
  434. def run(self, debug=True, blockThread=True):
  435. ''' start auto respond
  436. for option
  437. - debug: if set, debug info will be shown on screen
  438. it is defined in components/register.py
  439. '''
  440. raise NotImplementedError()
  441. def search_friends(self, name=None, userName=None, remarkName=None, nickName=None,
  442. wechatAccount=None):
  443. return self.storageClass.search_friends(name, userName, remarkName,
  444. nickName, wechatAccount)
  445. def search_chatrooms(self, name=None, userName=None):
  446. return self.storageClass.search_chatrooms(name, userName)
  447. def search_mps(self, name=None, userName=None):
  448. return self.storageClass.search_mps(name, userName)