im_exporter 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -3
- data/Rakefile +39 -1
- data/bin/im_exporter +12 -20
- data/im_porter.gemspec +19 -14
- data/lib/im_exporter/attachment.rb +10 -5
- data/lib/im_exporter/contact.rb +13 -9
- data/lib/im_exporter/message.rb +30 -9
- data/lib/im_exporter/version.rb +3 -2
- metadata +90 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 294b25e2f2c3b7e562a92bd3f6d8b0da056f2835
|
4
|
+
data.tar.gz: 876ab119887ca331fa73cc88e3623f566f473ee0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6806f84f932e78feffeb029f0b21ffbac8f8725e863dc6057af9c7cea03368310d6670634cf07b8d51c5ad00a14c1b3e1614202e2e5a4bfc3408bdff09a20598
|
7
|
+
data.tar.gz: ece83a1ef28d566744a29a1976f21f9affa835d3d596d9ae982f5edb83c2e6113ba0483956d95aae25889aaa600aa619363fe43ec89960a9788265be90f1204d
|
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
[](http://badge.fury.io/rb/im_exporter)
|
2
|
+
[](https://gemnasium.com/noqcks/im_exporter)
|
3
|
+
|
1
4
|
# im_exporter CLI
|
2
5
|
|
3
|
-
im_porter is an **iM**esasge **exporter** that backs up iMessage conversations to PDF or TXT files for easy reading and
|
6
|
+
im_porter is an **iM**esasge **exporter** that backs up iMessage conversations to PDF or TXT files for easy reading and searching
|
4
7
|
|
5
8
|
## Installation
|
6
9
|
|
7
10
|
Install from the command line via
|
8
11
|
|
9
|
-
|
12
|
+
```gem install im_exporter```
|
10
13
|
|
11
14
|
## Usage
|
12
15
|
|
@@ -18,9 +21,10 @@ will output iMessage conversations in PDF documents in the pwd
|
|
18
21
|
|
19
22
|
1. format PDF messages nicely so they look like a real iMessage conversation
|
20
23
|
2. refactor code so it doesn't look like complete shit
|
24
|
+
3. limit export to a specific phone number or contact name
|
21
25
|
|
22
26
|
## License
|
23
27
|
|
24
28
|
Copyright (C) 2015 Ben Visser
|
25
29
|
|
26
|
-
Released under the MIT License.
|
30
|
+
Released under the MIT License.
|
data/Rakefile
CHANGED
@@ -1 +1,39 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
require 'reek/rake/task'
|
4
|
+
require 'roodi_task'
|
5
|
+
|
6
|
+
task audit: [:style, :complexity, :duplication, :design, :documentation]
|
7
|
+
|
8
|
+
task style: [:rubocop]
|
9
|
+
|
10
|
+
desc 'Enforce Style Conformance with RuboCop'
|
11
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
12
|
+
task.patterns = ['lib/**/*.rb']
|
13
|
+
task.fail_on_error = false
|
14
|
+
end
|
15
|
+
|
16
|
+
task complexity: [:flog]
|
17
|
+
|
18
|
+
desc 'Assess Complexity with Flog'
|
19
|
+
# FlogTask.new :flog, 9000, ['lib']
|
20
|
+
task :flog do
|
21
|
+
sh 'flog lib/**/*.rb'
|
22
|
+
end
|
23
|
+
|
24
|
+
task duplication: [:flay]
|
25
|
+
|
26
|
+
task :flay do
|
27
|
+
sh 'flay'
|
28
|
+
end
|
29
|
+
|
30
|
+
task design: [:roodi, :reek]
|
31
|
+
|
32
|
+
desc 'Find Code Smells with Reek'
|
33
|
+
Reek::Rake::Task.new(:reek) do |task|
|
34
|
+
task.fail_on_error = false
|
35
|
+
end
|
36
|
+
|
37
|
+
task :documentation do
|
38
|
+
sh 'inch'
|
39
|
+
end
|
data/bin/im_exporter
CHANGED
@@ -1,34 +1,34 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'im_exporter'
|
4
|
-
|
5
4
|
require 'commander/import'
|
6
|
-
require 'sqlite3'
|
7
5
|
require 'prawn'
|
8
6
|
require 'etc'
|
7
|
+
require 'sqlite3'
|
9
8
|
|
10
|
-
program :name,
|
11
|
-
program :version,
|
9
|
+
program :name, 'iMessage Exporter CLI'
|
10
|
+
program :version, IMExporter::VERSION
|
12
11
|
program :description, 'Exports iMessage conversations as TEXT or PDF files'
|
13
12
|
program :help, 'Authors', 'Ben Visser <theodore.r.visser@gmail.com>'
|
14
13
|
program :help, 'Website', 'https://github.com/noqcks/im_exporter'
|
15
14
|
default_command :help
|
16
15
|
|
17
|
-
$chat_db = SQLite3::Database.new "/Users/#{Etc.getlogin}/Library/Messages/chat.db"
|
18
16
|
$user_db = SQLite3::Database.new "/Users/#{Etc.getlogin}/Library/Application Support/AddressBook/AddressBook-v22.abcddb"
|
17
|
+
$chat_db = SQLite3::Database.new "/Users/#{Etc.getlogin}/Library/Messages/chat.db"
|
19
18
|
|
20
19
|
command :export do |c|
|
21
20
|
c.syntax = 'export [options]'
|
22
21
|
c.description = 'Begin the export of iMessages into a desired format'
|
23
22
|
c.option '-f', '--format STRING', String, 'The type of format you want the iMessages outputted to [PDF, TXT]'
|
24
|
-
c.action do |
|
25
|
-
options.default :
|
23
|
+
c.action do |_, options|
|
24
|
+
options.default format: 'PDF'
|
25
|
+
|
26
|
+
contact = IMExporter::Contact
|
27
|
+
message = IMExporter::Message
|
28
|
+
attachment = IMExporter::Attachment
|
26
29
|
|
27
|
-
contact
|
28
|
-
message = IM_Exporter::Message
|
29
|
-
attachment = IM_Exporter::Attachment
|
30
|
+
contact.contact_ids.each do |contact_row|
|
30
31
|
|
31
|
-
contact.get_contact_ids.each do |contact_row|
|
32
32
|
$pdf = Prawn::Document.new if options.format.eql? 'PDF'
|
33
33
|
id = contact_row[0]
|
34
34
|
phone = contact_row[1].delete '+'
|
@@ -36,15 +36,7 @@ command :export do |c|
|
|
36
36
|
messages = 0
|
37
37
|
message.read(id).each do |message_row|
|
38
38
|
messages += 1
|
39
|
-
|
40
|
-
attachment.write(message_row[3]) if options.format.eql? 'PDF'
|
41
|
-
else
|
42
|
-
if message.is_from_me?(message_row[0])
|
43
|
-
message.write("me", message_row[1], contact_name, options.format)
|
44
|
-
else
|
45
|
-
message.write(contact_name, message_row[1], contact_name, options.format)
|
46
|
-
end
|
47
|
-
end if message_row[4].nil?
|
39
|
+
message.write_logic(message_row, contact_name, options.format)
|
48
40
|
end
|
49
41
|
if options.format.eql? 'PDF'
|
50
42
|
$pdf.render_file "#{contact_name}.pdf" unless messages.eql? 0
|
data/im_porter.gemspec
CHANGED
@@ -4,25 +4,30 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'im_exporter/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
-
spec.version =
|
9
|
-
spec.authors = [
|
10
|
-
spec.email =
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
7
|
+
spec.name = 'im_exporter'
|
8
|
+
spec.version = IMExporter::VERSION
|
9
|
+
spec.authors = ['Ben Visser']
|
10
|
+
spec.email = 'theodore.r.visser@gmail.com'
|
11
|
+
spec.summary = 'iMessage Exporter'
|
12
|
+
spec.description = 'Export iMessage conversations into TXT or PDF files'
|
13
|
+
spec.homepage = 'https://github.com/noqcks/im_exporter'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files
|
17
|
-
spec.executables =
|
16
|
+
spec.files = `git ls-files`.split("\n")
|
17
|
+
spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'commander', '~> 4.3', '>= 4.3.3'
|
22
22
|
spec.add_runtime_dependency 'sqlite3', '~> 1.3.10', '>= 1.3.10'
|
23
23
|
spec.add_runtime_dependency 'prawn', '~> 2.0.1', '>= 2.0.1'
|
24
|
-
spec.add_runtime_dependency 'etc', '~> 0.2.0'
|
24
|
+
spec.add_runtime_dependency 'etc', '~> 0.2.0', '>= 0.2.0'
|
25
25
|
|
26
|
-
spec.add_development_dependency '
|
27
|
-
spec.add_development_dependency '
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'rubocop'
|
28
|
+
spec.add_development_dependency 'flog'
|
29
|
+
spec.add_development_dependency 'flay'
|
30
|
+
spec.add_development_dependency 'roodi'
|
31
|
+
spec.add_development_dependency 'reek'
|
32
|
+
spec.add_development_dependency 'inch'
|
28
33
|
end
|
@@ -1,18 +1,23 @@
|
|
1
|
-
|
1
|
+
# Export iMessage conversations into TXT or PDF files
|
2
|
+
module IMExporter
|
3
|
+
# A module to handle attachments from the iMessage sqlite database
|
2
4
|
module Attachment
|
5
|
+
# writes attachments (images) out to a PDF or TXT file
|
3
6
|
def self.write(attachment_id)
|
4
|
-
|
7
|
+
query = 'select a.filename from attachment as a join message as m on m.date = a.created_date where m.rowid=?'
|
8
|
+
$chat_db.execute(query, attachment_id) do |file_dir|
|
5
9
|
file = file_dir.join('').sub!('~', '/Users/benvisser')
|
6
10
|
if self.supported_file_type?(file)
|
7
|
-
$pdf.image file, :
|
11
|
+
$pdf.image file, height: 250
|
8
12
|
else
|
9
|
-
$pdf.text
|
13
|
+
$pdf.text '[IMAGE-TYPE NOT SUPPORTED]'
|
10
14
|
end
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
18
|
+
# checks whether the attachment is supported by prawn
|
14
19
|
def self.supported_file_type?(file)
|
15
|
-
|
20
|
+
if file.include?('JPG') || file.include?('PNG') then true else false end
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
data/lib/im_exporter/contact.rb
CHANGED
@@ -1,24 +1,28 @@
|
|
1
|
-
|
1
|
+
# Export iMessage conversations into TXT or PDF files
|
2
|
+
module IMExporter
|
3
|
+
# A module to handle contact lists from the iMessage sqlite database
|
2
4
|
module Contact
|
5
|
+
# returns a contact name from a string that includes the contact's name and phone number
|
3
6
|
def self.parse_contact_name_from_string(row)
|
4
|
-
|
7
|
+
row.select { |element| row.count(element) > 1 }.uniq.select { |string| string[/[a-zA-Z]/] }.join(' ')
|
5
8
|
end
|
6
9
|
|
10
|
+
# returns the name of the contact with the specified ID and Phone number
|
7
11
|
def self.name(id, phone)
|
8
12
|
name = id
|
9
|
-
|
13
|
+
query = 'select ZSTRINGFORINDEXING from ZABCDCONTACTINDEX'
|
14
|
+
$user_db.execute(query) do |contact|
|
10
15
|
row = contact.join('').split(' ')
|
11
16
|
contact_name = self.parse_contact_name_from_string(row)
|
12
17
|
contact_phone = row.last
|
13
|
-
if contact_phone.eql? phone
|
14
|
-
name = contact_name
|
15
|
-
end
|
18
|
+
if contact_phone.eql? phone then name = contact_name end
|
16
19
|
end
|
17
|
-
|
20
|
+
name
|
18
21
|
end
|
19
22
|
|
20
|
-
|
21
|
-
|
23
|
+
# returns all contact IDs within the iMessage sqlitedb
|
24
|
+
def self.contact_ids
|
25
|
+
$chat_db.execute('select ROWID, id from handle')
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
data/lib/im_exporter/message.rb
CHANGED
@@ -1,25 +1,46 @@
|
|
1
|
-
|
1
|
+
# Export iMessage conversations into TXT or PDF files
|
2
|
+
module IMExporter
|
3
|
+
# A module to handle messages from the iMessage sqlite database
|
2
4
|
module Message
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
# writes the iMessage to a PDF or TXT document
|
6
|
+
def self.write(user, message, file_name, file_type)
|
7
|
+
if file_type.eql? 'PDF'
|
8
|
+
$pdf.font('/Library/Fonts/Times New Roman.ttf') do
|
6
9
|
$pdf.text "#{user}: #{message}"
|
7
10
|
end
|
8
11
|
else
|
9
|
-
File.open("#{file_name}.txt", 'a') {|
|
12
|
+
File.open("#{file_name}.txt", 'a') { |file| file.write("#{user}: #{message}\n") }
|
10
13
|
end
|
11
14
|
end
|
12
15
|
|
16
|
+
# gets metadata about each iMessage
|
13
17
|
def self.read(id)
|
14
|
-
|
18
|
+
select_rows = 'is_from_me, text, cache_has_attachments, rowid, cache_roomnames'
|
19
|
+
query = "select #{select_rows} from message where handle_id= ?"
|
20
|
+
$chat_db.execute(query, id)
|
15
21
|
end
|
16
22
|
|
23
|
+
# the logic behind how things get written to the document
|
24
|
+
def self.write_logic(message_row, contact_name, file_type)
|
25
|
+
if self.is_an_attachment?(message_row[2])
|
26
|
+
IMExporter::Attachment.write(message_row[3]) if file_type.eql? 'PDF'
|
27
|
+
else
|
28
|
+
if self.is_from_me?(message_row[0])
|
29
|
+
self.write('me', message_row[1], contact_name, file_type)
|
30
|
+
else
|
31
|
+
self.write(contact_name, message_row[1], contact_name, file_type)
|
32
|
+
end
|
33
|
+
end if message_row[4].nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
# checks whether an iMessage is from yourself
|
17
37
|
def self.is_from_me?(message)
|
18
|
-
|
38
|
+
if message.eql? 1 then true else false end
|
19
39
|
end
|
20
40
|
|
41
|
+
# checks whether the iMessage is actually an attachment (image)
|
21
42
|
def self.is_an_attachment?(message)
|
22
|
-
|
43
|
+
if message.eql? 1 then true else false end
|
23
44
|
end
|
24
45
|
end
|
25
|
-
end
|
46
|
+
end
|
data/lib/im_exporter/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: im_exporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Visser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -77,6 +77,9 @@ dependencies:
|
|
77
77
|
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: 0.2.0
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.2.0
|
80
83
|
type: :runtime
|
81
84
|
prerelease: false
|
82
85
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -84,37 +87,109 @@ dependencies:
|
|
84
87
|
- - "~>"
|
85
88
|
- !ruby/object:Gem::Version
|
86
89
|
version: 0.2.0
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 0.2.0
|
87
93
|
- !ruby/object:Gem::Dependency
|
88
|
-
name:
|
94
|
+
name: rake
|
89
95
|
requirement: !ruby/object:Gem::Requirement
|
90
96
|
requirements:
|
91
|
-
- - "
|
97
|
+
- - ">="
|
92
98
|
- !ruby/object:Gem::Version
|
93
|
-
version: '
|
99
|
+
version: '0'
|
94
100
|
type: :development
|
95
101
|
prerelease: false
|
96
102
|
version_requirements: !ruby/object:Gem::Requirement
|
97
103
|
requirements:
|
98
|
-
- - "
|
104
|
+
- - ">="
|
99
105
|
- !ruby/object:Gem::Version
|
100
|
-
version: '
|
106
|
+
version: '0'
|
101
107
|
- !ruby/object:Gem::Dependency
|
102
|
-
name:
|
108
|
+
name: rubocop
|
103
109
|
requirement: !ruby/object:Gem::Requirement
|
104
110
|
requirements:
|
105
|
-
- - "
|
111
|
+
- - ">="
|
106
112
|
- !ruby/object:Gem::Version
|
107
|
-
version: '
|
113
|
+
version: '0'
|
108
114
|
type: :development
|
109
115
|
prerelease: false
|
110
116
|
version_requirements: !ruby/object:Gem::Requirement
|
111
117
|
requirements:
|
112
|
-
- - "
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
- !ruby/object:Gem::Dependency
|
122
|
+
name: flog
|
123
|
+
requirement: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
type: :development
|
129
|
+
prerelease: false
|
130
|
+
version_requirements: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: flay
|
137
|
+
requirement: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
type: :development
|
143
|
+
prerelease: false
|
144
|
+
version_requirements: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
- !ruby/object:Gem::Dependency
|
150
|
+
name: roodi
|
151
|
+
requirement: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
type: :development
|
157
|
+
prerelease: false
|
158
|
+
version_requirements: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
- !ruby/object:Gem::Dependency
|
164
|
+
name: reek
|
165
|
+
requirement: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
type: :development
|
171
|
+
prerelease: false
|
172
|
+
version_requirements: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
- !ruby/object:Gem::Dependency
|
178
|
+
name: inch
|
179
|
+
requirement: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0'
|
184
|
+
type: :development
|
185
|
+
prerelease: false
|
186
|
+
version_requirements: !ruby/object:Gem::Requirement
|
187
|
+
requirements:
|
188
|
+
- - ">="
|
113
189
|
- !ruby/object:Gem::Version
|
114
|
-
version: '
|
190
|
+
version: '0'
|
115
191
|
description: Export iMessage conversations into TXT or PDF files
|
116
|
-
email:
|
117
|
-
- theodore.r.visser@gmail.com
|
192
|
+
email: theodore.r.visser@gmail.com
|
118
193
|
executables:
|
119
194
|
- im_exporter
|
120
195
|
extensions: []
|
@@ -157,3 +232,4 @@ signing_key:
|
|
157
232
|
specification_version: 4
|
158
233
|
summary: iMessage Exporter
|
159
234
|
test_files: []
|
235
|
+
has_rdoc:
|