Last active
December 17, 2015 01:48
-
-
Save JerryFleming/5530647 to your computer and use it in GitHub Desktop.
Export SMS from you Android phones into HTML, friendly for webkit browsers (Chrome/Safari).
This file contains 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
#!/usr/bin/python3 | |
# Export SMS from you Android phones into HTML, friendly for webkit browsers (Chrome/Safari). | |
# This requires SL4A <https://code.google.com/p/android-scripting/> | |
# and Python3 <https://code.google.com/p/python-for-android/wiki/Python3>. | |
# by Jerry Fleming <[email protected]> on 2013-03-25. | |
# No rights reserved. Use at your own risk. | |
import sqlite3 | |
import datetime | |
import re | |
f = open('msg_%s.html' % str(datetime.date.today()), 'w') | |
def toTime(time, first=False): | |
time = str(datetime.datetime.fromtimestamp(int(time/1000))) | |
if first: return time.split()[0] | |
else: return time | |
rep = re.compile('\0|\x0c') | |
def txt(s): | |
s = rep.sub('', s.strip()) | |
s = s.replace('&', '&') | |
s = s.replace('<', '<') | |
s = s.replace('>', '>') | |
s = s.replace('"', '"') | |
return s | |
TYPES = { | |
1: 'get', | |
2: 'send', | |
} | |
names = {} | |
path = '/dbdata/databases/com.android.providers.' | |
con = sqlite3.connect(path + 'contacts/contacts2.db') | |
cur = con.cursor() | |
cur.execute('SELECT number, name FROM view_v1_phones') | |
nump = re.compile(' |-|^\+?86|^12520') | |
for row in cur: | |
num = nump.sub('', row[0]) | |
names[num] = row[1] | |
con = sqlite3.connect(path + 'telephony/mmssms.db') | |
cur = con.cursor() | |
cur1 = con.cursor() | |
f.write('''<?xml version="1.0" encoding="utf-8"?> | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=0"/> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> | |
<title>SMS '''+str(datetime.datetime.now())+'''</title> | |
<style> | |
* | |
{ | |
font-size: 14px; | |
} | |
.thread | |
{ | |
display: block; | |
padding: 5px 0px; | |
margin: 0px 0px 30px 0px; | |
position: relative; | |
} | |
.thread.off | |
{ | |
display: none; | |
} | |
.thread.on | |
{ | |
display: block; | |
} | |
.thread:before | |
{ | |
content: ""; | |
position: absolute; | |
width: 100%; | |
border-top: 1px solid black; | |
top: 22px; | |
z-index: 15; | |
} | |
.thread.on:before | |
{ | |
left: 0px; | |
top: 22px; | |
position: fixed; | |
} | |
.thread.on:after | |
{ | |
left: 0px; | |
top: 0px; | |
width: 100%; | |
height: 40px; | |
opacity: .4; | |
z-index: 10; | |
background-color: white; | |
content: ""; | |
position: fixed; | |
} | |
.thread.on .header | |
{ | |
position: fixed; | |
left: 60px; | |
} | |
.thread.on .message | |
{ | |
margin-top: 40px; | |
} | |
.header | |
{ | |
position: absolute; | |
z-index: 20; | |
top: 10px; | |
left: 50px; | |
border: 1px solid black; | |
padding: 3px; | |
background-color: white; | |
display: block; | |
} | |
.control | |
{ | |
position: absolute; | |
top: -4px; | |
left: -40px; | |
cursor: pointer; | |
width: 30px; | |
height: 30px; | |
border-radius: 15px; | |
background-color: green; | |
} | |
.control:before | |
{ | |
content: ""; | |
position: absolute; | |
top: 1px; | |
left: 1px; | |
cursor: pointer; | |
width: 28px; | |
height: 28px; | |
border-radius: 14px; | |
background-color: white; | |
} | |
.control:after | |
{ | |
content: ""; | |
position: absolute; | |
border: 9px solid transparent; | |
border-left-color: black; | |
border-right: 0; | |
border-left-width: 14px; | |
top: 6px; | |
left: 10px; | |
width: 0; | |
height: 0; | |
display: block; | |
} | |
.control.on:after | |
{ | |
content: ""; | |
position: absolute; | |
border: 9px solid transparent; | |
border-top-color: black; | |
border-bottom: 0; | |
border-top-width: 14px; | |
top: 10px; | |
left: 6px; | |
width: 0; | |
height: 0; | |
display: block; | |
} | |
.header .name | |
{ | |
font-weight: bold; | |
} | |
.date | |
{ | |
color: gray; | |
font-size: 12px; | |
} | |
.header .address | |
{ | |
color: blue; | |
} | |
.count | |
{ | |
font-size: 12px; | |
display: block; | |
position: absolute; | |
right: -80px; | |
background: white; | |
border: 1px solid black; | |
border-radius: 3px; | |
padding: 2px; | |
top: 2px; | |
} | |
.count:before | |
{ | |
content: "共"; | |
} | |
.count:after | |
{ | |
content: "条"; | |
} | |
.entries | |
{ | |
display: none; | |
} | |
.message | |
{ | |
display: block; | |
border-radius: 5px; | |
width: 80%; | |
margin: 15px; | |
padding: 10px; | |
padding-bottom: 25px; | |
-webkit-box-shadow: 3px 3px 8px #000; | |
position: relative; | |
} | |
.message .date | |
{ | |
display: block; | |
position: absolute; | |
right: 10px; | |
bottom: 10px; | |
font-size: 12px; | |
} | |
.message.get | |
{ | |
border: 1px solid #ccaf61; | |
background: -webkit-gradient(linear, left top, left bottom, | |
color-stop(0, #fbf394), | |
color-stop(100%, #f9dd59) | |
); | |
margin-right: auto; | |
} | |
.message.send | |
{ | |
border: 1px solid #8dc754; | |
background: -webkit-gradient(linear, left top, left bottom, | |
color-stop(0, #e0fa9d), | |
color-stop(100%, #aaed86) | |
); | |
margin-left: auto; | |
} | |
</style> | |
</head> | |
<body> | |
''') | |
cur.execute('SELECT _id, date, message_count FROM threads ORDER BY date DESC') | |
for thread in cur: | |
cur1.execute('SELECT address, date, type, body FROM sms WHERE thread_id=? ORDER BY date DESC', (thread[0], )) | |
head = False | |
for msg in cur1: | |
if msg[2] not in (1, 2): continue | |
if not head: | |
address = nump.sub('', msg[0]) | |
if address in names: name = names[address] | |
f.write('<div class="thread">\n') | |
f.write(' <div class="header">\n') | |
f.write(' <div class="control"></div>\n') | |
if address in names: | |
name = names[address] | |
f.write(' <span class="name">%s</span>\n' % name) | |
f.write(' <span class="address">%s</span>\n' % address) | |
f.write(' <span class="date">%s</span>\n' % toTime(thread[1], True)) | |
f.write(' <span class="count">%s</span>\n' % thread[2]) | |
f.write(' </div>\n') | |
f.write(' <div class="entries">\n') | |
head = True | |
f.write(' <div class="message %s">\n' % TYPES[msg[2]]) | |
f.write(' <div class="content">%s</div>\n' % txt(msg[3])) | |
f.write(' <div class="date">%s</div>\n' % toTime(msg[1])) | |
f.write(' </div>\n') | |
if head: | |
f.write(' </div>\n') | |
f.write(' </div>\n') | |
f.write('''</body> | |
<script src="jquery.js"></script> | |
<script> | |
$('.control').click(function(){ | |
$(this).parent().next().toggle(); | |
$(this).toggleClass('on'); | |
if($(this).hasClass('on')) | |
{ | |
$('.thread').addClass('off'); | |
$(this).parent().parent().removeClass('off').addClass('on'); | |
} | |
else | |
{ | |
$('.thread').removeClass('off').removeClass('on'); | |
} | |
}); | |
</script> | |
</html>''') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment