-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
executable file
·139 lines (128 loc) · 2.83 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env node
import Knex from "knex"
import Yargs from "yargs"
import {hideBin} from "yargs/helpers"
// apple have made their own epoch, the first of jan 2001
let applepoch = new Date("2001-01-01").getTime()
// they save their dates in microseconds since that epoch, so we add their
// epoch to the date and divide it by a million to make it like a unix date,
// which is the number of seconds since 1970-01-01
let convertAppleDateToIsoDate = date => {
return new Date(applepoch + date / 1000000).toISOString()
}
function getKnex() {
let knex
return function (filename) {
if (!knex) {
knex = Knex({
client: "better-sqlite3",
useNullAsDefault: true,
connection: {
filename
}
})
}
return knex
}
}
let knex = getKnex()
let yargs = Yargs(hideBin(process.argv))
yargs
.command({
command: "extract <database> <handle> [name] [me]",
describe: "extract messages for a handle",
builder(yargs) {
return yargs
.positional(
"database",
{
describe: "chat.db (found at ~/Library/Messages/chat.db)",
type: "string"
}
)
.positional(
"handle",
{
describe:
"the handle whose messages to extract (see list-handles)",
type: "string"
}
)
.positional(
"name",
{
describe: "the name to use for `handle`",
type: "string"
}
)
.positional(
"me",
{
describe: "the name to use for `me`",
type: "string",
default: "me"
}
)
},
handler: extract
})
.command({
command: "list-handles <database>",
aliases: ["handles"],
describe: "list handles (like, contacts) from the database",
builder(yargs) {
return yargs
.positional(
"database",
{
describe: "chat.db (found at ~/Library/Messages/chat.db)",
type: "string"
}
)
},
async handler(argv) {
await knex(argv.database)
.select("*")
.from("handle")
.then(handles =>
handles.forEach(handle =>
process.stdout.write(handle.id + "\n")))
process.exit(0)
}
})
.demandCommand(1, "you gotta chose a command")
.help()
.wrap(yargs.terminalWidth())
.argv
async function extract(argv) {
let handle = argv.handle.trim()
let messages = await knex(argv.database)
.select([
"text",
"is_from_me",
"date",
"service",
])
.from("message")
.whereIn(
"handle_id",
knex(argv.database)
.select("ROWID")
.from("handle")
.where({
id: handle
})
)
.orderBy("date", "asc")
.then(messages => {
messages.forEach(message => {
message.date = convertAppleDateToIsoDate(message.date)
message.from = message.is_from_me ? argv.me : argv.name
message.to = message.is_from_me ? argv.name : argv.me
delete message.is_from_me
})
return messages
})
process.stdout.write(JSON.stringify(messages, 0, "\t") + "\n")
process.exit(0)
}