|
23 | 23 | # URLs |
24 | 24 | LoginURL ="https://m.facebook.com/login.php?login_attempt=1" |
25 | 25 | SearchURL ="https://www.facebook.com/ajax/typeahead/search.php" |
26 | | -SendURL ="https://www.facebook.com/ajax/mercury/send_messages.php" |
| 26 | +#SendURL ="https://www.facebook.com/ajax/mercury/send_messages.php" |
| 27 | +SendURL ="https://www.facebook.com/messaging/send/" |
27 | 28 | ThreadsURL ="https://www.facebook.com/ajax/mercury/threadlist_info.php" |
28 | 29 | ThreadSyncURL="https://www.facebook.com/ajax/mercury/thread_sync.php" |
29 | 30 | MessagesURL ="https://www.facebook.com/ajax/mercury/thread_info.php" |
@@ -220,63 +221,75 @@ def getUsers(self, name): |
220 | 221 |
|
221 | 222 | return users # have bug TypeError: __repr__ returned non-string (type bytes) |
222 | 223 |
|
223 | | - def send(self, thread_id, message=None, like=None): |
| 224 | + def send(self, recipient_id, message=None, message_type='user', like=None, image_id=None): |
224 | 225 | """Send a message with given thread id |
225 | | -
|
226 | | - :param thread_id: a thread id that you want to send a message |
| 226 | + :param recipient_id: the user id or thread id that you want to send a message to |
227 | 227 | :param message: a text that you want to send |
| 228 | + :param message_type: determines if the recipient_id is for user or thread |
228 | 229 | :param like: size of the like sticker you want to send |
| 230 | + :param image_id: id for the image to send, gotten from the UploadURL |
229 | 231 | """ |
230 | 232 |
|
| 233 | + if message_type.lower() == 'group': |
| 234 | + thread_id = recipient_id |
| 235 | + user_id = None |
| 236 | + else: |
| 237 | + thread_id = None |
| 238 | + user_id = recipient_id |
| 239 | + |
| 240 | + messageAndOTID=generateOfflineThreadingID() |
231 | 241 | timestamp = now() |
232 | 242 | date = datetime.now() |
233 | | - ## see https://github.com/Schmavery/facebook-chat-api/blob/master/src/sendMessage.js |
234 | 243 | data = { |
235 | | - 'client' : self.client, |
236 | | - 'message_batch[0][action_type]' : 'ma-type:user-generated-message', |
237 | | - 'message_batch[0][author]' : 'fbid:' + str(self.uid), |
238 | | - #'message_batch[0][specific_to_list][0]' : 'fbid:' + str(thread_id), |
239 | | - #'message_batch[0][specific_to_list][1]' : 'fbid:' + str(self.uid), |
240 | | - 'message_batch[0][timestamp]' : timestamp, |
241 | | - 'message_batch[0][timestamp_absolute]' : 'Today', |
242 | | - 'message_batch[0][timestamp_relative]' : str(date.hour) + ":" + str(date.minute).zfill(2), |
243 | | - 'message_batch[0][timestamp_time_passed]' : '0', |
244 | | - 'message_batch[0][is_unread]' : False, |
245 | | - 'message_batch[0][is_cleared]' : False, |
246 | | - 'message_batch[0][is_forward]' : False, |
247 | | - 'message_batch[0][is_filtered_content]' : False, |
248 | | - 'message_batch[0][is_spoof_warning]' : False, |
249 | | - 'message_batch[0][source]' : 'source:chat:web', |
250 | | - 'message_batch[0][source_tags][0]' : 'source:chat', |
251 | | - 'message_batch[0][body]' : message, |
252 | | - 'message_batch[0][html_body]' : False, |
253 | | - 'message_batch[0][ui_push_phase]' : 'V3', |
254 | | - 'message_batch[0][status]' : '0', |
255 | | - 'message_batch[0][message_id]' : generateMessageID(self.client_id), |
256 | | - 'message_batch[0][manual_retry_cnt]' : '0', |
257 | | - 'message_batch[0][thread_fbid]' : None, |
258 | | - 'message_batch[0][has_attachment]' : False, |
| 244 | + 'client': self.client, |
| 245 | + 'action_type' : 'ma-type:user-generated-message', |
| 246 | + 'author' : 'fbid:' + str(self.uid), |
| 247 | + 'timestamp' : timestamp, |
| 248 | + 'timestamp_absolute' : 'Today', |
| 249 | + 'timestamp_relative' : str(date.hour) + ":" + str(date.minute).zfill(2), |
| 250 | + 'timestamp_time_passed' : '0', |
| 251 | + 'is_unread' : False, |
| 252 | + 'is_cleared' : False, |
| 253 | + 'is_forward' : False, |
| 254 | + 'is_filtered_content' : False, |
| 255 | + 'is_filtered_content_bh': False, |
| 256 | + 'is_filtered_content_account': False, |
| 257 | + 'is_filtered_content_quasar': False, |
| 258 | + 'is_filtered_content_invalid_app': False, |
| 259 | + 'is_spoof_warning' : False, |
| 260 | + 'source' : 'source:chat:web', |
| 261 | + 'source_tags[0]' : 'source:chat', |
| 262 | + 'body' : message, |
| 263 | + 'html_body' : False, |
| 264 | + 'ui_push_phase' : 'V3', |
| 265 | + 'status' : '0', |
| 266 | + 'offline_threading_id':messageAndOTID, |
| 267 | + 'message_id' : messageAndOTID, |
| 268 | + 'threading_id':generateMessageID(self.client_id), |
| 269 | + 'ephemeral_ttl_mode:': '0', |
| 270 | + 'manual_retry_cnt' : '0', |
| 271 | + 'signatureID' : getSignatureID(), |
| 272 | + 'has_attachment' : image_id != None, |
| 273 | + 'other_user_fbid' : recipient_id, |
| 274 | + 'specific_to_list[0]' : 'fbid:' + str(recipient_id), |
| 275 | + 'specific_to_list[1]' : 'fbid:' + str(self.uid), |
259 | 276 | } |
260 | | - if self.last_isgroup: |
261 | | - data['message_batch[0][thread_fbid]'] = thread_id |
262 | | - else: |
263 | | - data['message_batch[0][other_user_fbid]'] = thread_id |
264 | | - data['message_batch[0][specific_to_list][0]'] = 'fbid:' + str(thread_id) |
265 | | - data['message_batch[0][specific_to_list][1]'] = 'fbid:' + str(self.uid) |
266 | | - |
267 | | - |
| 277 | + |
| 278 | + if image_id: |
| 279 | + data['message_batch[0][image_ids][0]'] = image_id |
| 280 | + |
268 | 281 | if like: |
269 | 282 | try: |
270 | 283 | sticker = LIKES[like.lower()] |
271 | 284 | except KeyError: |
272 | 285 | # if user doesn't enter l or m or s, then use the large one |
273 | 286 | sticker = LIKES['l'] |
274 | 287 | data["message_batch[0][sticker_id]"] = sticker |
275 | | - |
276 | | - open("send_data.txt","a").write(str(data)+"\n") |
| 288 | + |
277 | 289 | r = self._post(SendURL, data) |
278 | 290 | return r.ok |
279 | 291 |
|
| 292 | + |
280 | 293 | def getThreadInfo(self, userID, start, end=None): |
281 | 294 | """Get the info of one Thread |
282 | 295 |
|
@@ -452,131 +465,12 @@ def _parseTimeInMessage(self,metadata): |
452 | 465 |
|
453 | 466 | return self._parseTime(msgtime) |
454 | 467 |
|
455 | | - """ for testing new _parseMessage() code |
456 | | - def _parseGroupMessage(self,metadata): |
457 | | - if 'delta' in metadata['type']: |
458 | | - thread_fbid = metadata['delta']['messageMetadata']['threadKey']['threadFbId'] |
459 | | - message=metadata['delta']['body'] |
460 | | - mid = metadata['delta']['messageMetadata']['messageId'] |
461 | | - sender_fbid = metadata['delta']['messageMetadata']['actorFbId'] |
462 | | - thread_name = thread_fbid |
463 | | - sender_name = sender_fbid |
464 | | - if thread_fbid in self.roster.keys(): self.last_tname = self._roster(thread_fbid) |
465 | | - if sender_fbid in self.roster.keys(): sender_name = self._roster(fbid) |
466 | | - elif 'messaging' in metadata['type']: |
467 | | - thread_fbid = metadata['message']['thread_fbid'] |
468 | | - message=metadata['message']['body'] |
469 | | - mid = metadata['message']['mid'] |
470 | | - thread_name = metadata['message']['group_thread_info']['name'] |
471 | | - sender_fbid = metadata['message']['sender_fbid'] |
472 | | - sender_name = metadata['message']['sender_name'] |
473 | | - self._roster(thread_fbid,thread_name) |
474 | | - self._roster(sender_fbid,sender_name) |
475 | | - #print("_parsePersonalMessage(): get "+message) |
476 | | - #print(mid) |
477 | | - return message,mid,thread_fbid,sender_fbid |
478 | | - |
479 | | - def _parsePersonalMessage(self,metadata): |
480 | | - if metadata['type'] in ['delta']: |
481 | | - mid = metadata['delta']['messageMetadata']['messageId'] |
482 | | - fbid = metadata['delta']['messageMetadata']['actorFbId'] |
483 | | - if 'body' in metadata['delta'].keys(): |
484 | | - message = metadata['delta']['body'] |
485 | | - else: |
486 | | - print("get sticker") |
487 | | - message = ['delta']['attachments'][0]['mercury']['url'] |
488 | | - elif metadata['type'] in ['m_messaging', 'messaging']: |
489 | | - mid = metadata['message']['mid'] |
490 | | - message=metadata['message']['body'] |
491 | | - if 'sender_fbid' in metadata['message'].keys(): |
492 | | - fbid = metadata['message']['sender_fbid'] |
493 | | - else: |
494 | | - fbid = metadata['message']['threadKey']['otherUserFbId'] |
495 | | - if 'sender_name' in metadata['message'].keys(): |
496 | | - name = metadata['message']['sender_name'] |
497 | | - self._roster(fbid,name) |
498 | | - #print("_parsePersonalMessage(): get "+message) |
499 | | - #print(mid) |
500 | | - return message,mid,fbid |
501 | | -
|
502 | | - def _isDeltaMsg(self,m): |
503 | | - if m['type'] in ['delta'] : return True |
504 | | - return False |
505 | | - def _parseMessage(self, content): |
506 | | - ''' |
507 | | - Get message and author name from content. |
508 | | - May contains multiple messages in the content. |
509 | | - ''' |
510 | | - if 'ms' not in content: return |
511 | | - for m in content['ms']: |
512 | | - if m['type'] in ['m_messaging', 'messaging'] or self._isDeltaMsg(m): |
513 | | - thread_id = '' |
514 | | - mid = '' |
515 | | - sender_fbid = '' |
516 | | - try: |
517 | | - message,mid,thread_id,sender_fbid = self._parseGroupMessage(m) |
518 | | - except: |
519 | | - print("_parseGroupMessage():") |
520 | | - print(exc_info()) |
521 | | - print(m) |
522 | | - pass |
523 | | -
|
524 | | - if not mid: |
525 | | - try: |
526 | | - message,mid,sender_fbid = self._parsePersonalMessage(m) |
527 | | - except: |
528 | | - print("_parsePersonalMessage():") |
529 | | - print(exc_info()) |
530 | | - print(m) |
531 | | - pass |
532 | | - if not mid: # not message |
533 | | - #print "not message" |
534 | | - return |
535 | | -
|
536 | | - stickurl = "" |
537 | | - if not message: |
538 | | - try: |
539 | | - stickurl = metadata['message']['attachments'][0]['url'] |
540 | | -
|
541 | | - except: |
542 | | - pass |
543 | | - if mid == self.last_mid: |
544 | | - pass |
545 | | - else: |
546 | | - self.last_mid = mid |
547 | | - self.on_message(mid,message,sender_fbid,thread_id,self._parseTimeInMessage(m), stickurl) |
548 | | - elif m['type'] in ['typ']: |
549 | | - try: |
550 | | - fbid = m["from"] |
551 | | - self.on_typing(fbid) |
552 | | - except: |
553 | | - self._output_errlog('log.txt',str(m),str(exc_info())) |
554 | | - elif m['type'] in ['m_read_receipt']: |
555 | | - try: |
556 | | - # no author include in json # author = m['author'] |
557 | | - reader = m['reader'] |
558 | | - msgtime = m['time'] |
559 | | - self.on_read(reader, self._parseTime(msgtime),m) |
560 | | - except: |
561 | | - self._output_errlog('log.txt',str(m),str(exc_info())) |
562 | | - elif m['type'] in ['notification_json']: |
563 | | - try: |
564 | | - likemsg = m['nodes'][0]['unaggregatedTitle']['text'] |
565 | | - #likemsg = m['nodes'][0]['unaggregatedTitle']['text'] |
566 | | - self.on_notify(likemsg,m) |
567 | | - except : |
568 | | - self._output_errlog('like_err.log',str(m),str(exc_info())) |
569 | | - self.on_notify(u'some notification appear, see like_err.log',m) |
570 | | - else: |
571 | | - self._output_errlog('log.txt',str(m),"") |
572 | | - """ |
573 | | - |
574 | 468 | def _parse_pass(self,m): |
575 | 469 | pass |
576 | 470 | def _parse_delta_ReadReceipt(self,m): |
577 | 471 | '''actionTimestampMs,irisSeqId,threadKey[otherUserFbId],watermarkTimestampMs''' |
578 | 472 | try: |
579 | | - readerid = m['delta']['threadKey']['otherUserFbId'] |
| 473 | + readerid = m['delta']['threadKey'].get('otherUserFbId') or m['delta'].get('actorFbId') |
580 | 474 | msgtime = m['delta']['actionTimestampMs'] |
581 | 475 | self.on_read(readerid, self._parseTime(msgtime),m) |
582 | 476 | except : |
@@ -630,6 +524,7 @@ def _parse_typ(self,m): |
630 | 524 | ''' typing ''' |
631 | 525 | pass |
632 | 526 | def _parseMessage(self,content): |
| 527 | + if not content: return |
633 | 528 | ''' action by type ''' |
634 | 529 | adic = dict() |
635 | 530 | adic['delta'] = self._parse_delta |
@@ -657,6 +552,7 @@ def _parseMessage(self,content): |
657 | 552 | adic['share_reply'] = self._parse_pass |
658 | 553 | adic['sticker'] = self._parse_pass |
659 | 554 | adic['user'] = self._parse_pass |
| 555 | + adic['ttyp'] = self._parse_pass |
660 | 556 |
|
661 | 557 | if "refresh" in content.get("t"): |
662 | 558 | print("need refreshed?") |
|
0 commit comments