Last active
March 4, 2024 19:21
-
-
Save erickdsama/8b312635ca34770f69d08f58d65f69d1 to your computer and use it in GitHub Desktop.
Class to read and write messages to Whatsapp through of the ADB. You need a android Device with Sqlite3 installed and ADB service.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf-8 | |
import json | |
import time | |
from subprocess import check_output, CalledProcessError | |
class WHO: | |
FROM_ME = "key_from_me == 1" | |
OTHERS = "key_from_me != 1" | |
ALL = "" | |
class TYPE: | |
GPS = 1 | |
IMAGE = 2 | |
TEXT = 3 | |
class COLUMN: | |
_id = id = 0 | |
key_remote_jid = 1 | |
key_from_me = 2 | |
key_id = 3 | |
status = 4 | |
needs_push = 5 | |
data = message = 6 | |
timestamp = 7 | |
media_url = 8 | |
media_mime_type = 9 | |
media_wa_type = 10 | |
media_size = 11 | |
media_name = 12 | |
media_caption = 13 | |
media_hash = 14 | |
media_duration = 15 | |
origin = 16 | |
latitude = 17 | |
longitude = 18 | |
thumb_image = 19 | |
remote_resource = 20 | |
received_timestamp = 21 | |
send_timestamp = 22 | |
receipt_server_timestamp = 23 | |
receipt_device_timestamp = 24 | |
read_device_timestamp = 25 | |
played_device_timestamp = 26 | |
raw_data = 27 | |
recipient_count = 28 | |
participant_hash = 29 | |
starred = 30 | |
quoted_row_id = 31 | |
mentioned_jids = 32 | |
multicast_id = 33 | |
edit_version = 34 | |
media_enc_hash = 35 | |
payment_transaction_id = 36 | |
class RWAS: | |
"""Rest WhatsApp Application Service | |
Class to read and write messgaes directly to an android device [Sqlite3 is needed] | |
Args: | |
emulator (str): ID from your Android device, can be an Android phone or a Emulator with Sqlite3 installed. | |
Note: | |
if you only use one Device is not necesary pass the 'emulator' arg, It will be detected automatically | |
""" | |
def __init__(self, emulator=None): | |
self.emulator = emulator | |
def rwas_check_output(self, last_id=None, who=None): | |
if last_id is None: | |
query_str = " WHERE {}".format(who) if (who != WHO.ALL) else "" | |
else: | |
query_str = " AND {}".format(who) if (who != WHO.ALL) else "" | |
query_str = "WHERE _id>{} {}".format(last_id, query_str) | |
if self.emulator is None: | |
return check_output( | |
"adb shell 'sqlite3 /data/data/com.whatsapp/databases/msgstore.db \"select * from messages {};\"'".format(query_str), shell=True) | |
else: | |
return check_output( | |
"adb -s {} shell 'sqlite3 /data/data/com.whatsapp/databases/msgstore.db \"select * from messages {};\"'".format(self.emulator, query_str), shell=True) | |
def read(self, last_id=None, who=WHO.OTHERS): | |
""" Method to read the messages from the database of whatsapp | |
Args: | |
last_id (int): The last _id that do u want | |
who (WHO): Whos the message emitter | |
Note: | |
if you don't pass tha last_id param, returns all messages | |
Returns: | |
DATA if successful, None otherwise. | |
""" | |
try: | |
return self.DATA(self.rwas_check_output(last_id=last_id, who=who)) | |
except CalledProcessError as e: | |
return None | |
def send(self, message=None, location=None, remote_jid=None): | |
build_message = self.BuildMessage(message=message, location=None, remote_jid=remote_jid) | |
print build_message.chat_string | |
try: | |
print check_output("adb shell pkill com.whatsapp", shell=True) | |
print check_output("adb shell chmod 777 /data/data/com.whatsapp/databases/msgstore.db", shell=True) | |
print check_output(build_message.chat_string, shell=True) | |
print check_output(build_message.list_string, shell=True) | |
print check_output(build_message.update_string, shell=True) | |
print check_output("adb shell am start -n com.whatsapp/.Main", shell=True) | |
except CalledProcessError as e: | |
print e | |
class DATA: | |
def __init__(self, dumped=None): | |
self.dumped = dumped | |
def parse_to_array(self): | |
fields = [] | |
rows = self.dumped.split("|\r\n") | |
del rows[-1] | |
for row in rows: | |
elements = row.split("|") | |
fields.append(elements) | |
return fields | |
def parse_to_dict(self): | |
array = self.parse_to_array() | |
messages = [] | |
for row in array: | |
data = { | |
"_id": row[COLUMN.id], | |
"message": row[COLUMN.message], | |
"latitude": row[COLUMN.latitude], | |
"longitude": row[COLUMN.longitude], | |
"med_du": row[COLUMN.media_duration], | |
"key_remote_jid": row[COLUMN.key_remote_jid], | |
} | |
messages.append(data) | |
data = { | |
"messages": messages | |
} | |
return data | |
def parse_to_json(self): | |
""" Convert the data to JSON object | |
Returns: | |
A Json object of the data fetched | |
""" | |
return json.dumps(self.parse_to_dict(), ensure_ascii=False) | |
class BuildMessage: | |
def __init__(self, message=None, location=None, remote_jid=None): | |
self.location = location | |
self.message = message | |
self.remote_jid = remote_jid | |
@property | |
def chat_string(self): | |
"""str: Chat string query to insert """ | |
l1 = int(round(time.time() * 1000)) | |
l2 = int(l1 / 1000) | |
k = "-1150867590" | |
return """adb shell "sqlite3 /data/data/com.whatsapp/databases/msgstore.db \\"INSERT INTO messages (key_remote_jid, key_from_me, key_id, status, needs_push, data, timestamp, MEDIA_URL, media_mime_type, media_wa_type, MEDIA_SIZE, media_name , latitude, longitude, thumb_image, remote_resource, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, raw_data, media_hash, recipient_count, media_duration, origin) VALUES ('{}', 1,'{}-{}', 0,0, '{}',{},'','', 0, 0,'', 0.0,0.0,'','',{}, -1, -1, -1,0 ,'',0,0,0);\\"" | |
""".format(self.remote_jid, l2, k, self.message, l1, l1) | |
@property | |
def list_string(self): | |
"""str: List chat query to insert """ | |
return """ adb shell "sqlite3 /data/data/com.whatsapp/databases/msgstore.db \\"insert into chat_list (key_remote_jid) select '{0}' where not exists (select 1 from chat_list where key_remote_jid='{0}');\\"" """.format( | |
self.remote_jid) | |
@property | |
def update_string(self): | |
"""str: List chat query to update based on list insert """ | |
return """ adb shell "sqlite3 /data/data/com.whatsapp/databases/msgstore.db \\"update chat_list set message_table_id = (select max(messages._id) from messages) where chat_list.key_remote_jid='{}';\\"" """.format( | |
self.remote_jid) |
Hi Erick
Could it be that your script doesnt work anymore with the a new version of whatsapp? Which version have you used, when your script still worked. Do you remember?
Brigado!
This happens when I call the send.message function.
b''
b''
b'Error: no such table: messages\r\n'
b'Error: no such table: chat_list\r\n'
b'Error: no such table: chat_list\r\n'
b'Starting: Intent { cmp=com.whatsapp/.Main }\r\n'
seems like the database of whatsapp has changed.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Erick
Thank you for your script. Awesome!
Saidly I get the following error when I run rwas.py with the following lines inside rwas.py.
rwas_service = RWAS(emulator=None) # class call
rwas_service.read(last_id=None).parse_to_json() # to read all on and parse to json
rwas_service.send(message="Hello world from mexico", remote_jid="[email protected]") # to send change the remote_jid
Any idea why it doesnt work?
ERROR
thomas$ python3 rwas.py
Traceback (most recent call last):
File "/Users/thomas/rwas.py", line 190, in
rwas_service.read(last_id=None).parse_to_json() # to read all on and parse to json
File "/Users/thomas/rwas.py", line 157, in parse_to_json
return json.dumps(self.parse_to_dict(), ensure_ascii=False)
File "/Users/thomas/rwas.py", line 135, in parse_to_dict
array = self.parse_to_array()
File "/Users/thomas/rwas.py", line 127, in parse_to_array
rows = self.dumped.split("|\r\n")
TypeError: a bytes-like object is required, not 'str'