runoff 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +29 -15
- data/README.md +9 -3
- data/bin/runoff +26 -53
- data/lib/runoff/adapters/adapter.rb +31 -0
- data/lib/runoff/adapters/json_adapter.rb +88 -0
- data/lib/runoff/adapters/txt_adapter.rb +69 -0
- data/lib/runoff/chat.rb +38 -0
- data/lib/runoff/commandline/all.rb +53 -0
- data/lib/runoff/commandline/command.rb +34 -0
- data/lib/runoff/commandline/none.rb +45 -0
- data/lib/runoff/commandline/some.rb +84 -0
- data/lib/runoff/file_writer.rb +37 -58
- data/lib/runoff/location.rb +23 -20
- data/lib/runoff/version.rb +1 -1
- data/lib/runoff.rb +12 -4
- data/runoff.gemspec +0 -1
- data/test/command_all_test.rb +90 -0
- data/test/command_some_test.rb +49 -0
- data/test/data/custom_location/test_main.db +0 -0
- data/test/data/test_main.db +0 -0
- data/test/location_test.rb +78 -0
- metadata +21 -25
- data/lib/runoff/commands/all.rb +0 -22
- data/lib/runoff/commands/command.rb +0 -19
- data/lib/runoff/commands/some.rb +0 -38
- data/lib/runoff/skype_data_format.rb +0 -128
- data/test/skype_data_format_test.rb +0 -58
- data/test/test_db.sqlite +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4aeef27e77018f295faf0e6f43909ddf9516f71
|
4
|
+
data.tar.gz: 13d13befb22b12e797673c36448a44dfed2467e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a739d9f63e5176c2563de12886bf4bfcddaf955446e55a6a714d734710e3a3743218569ca6fd78c25677f598eb2fed56b04fd6ccf8e3d04632fa78d9bf2d835
|
7
|
+
data.tar.gz: d58f520e774251942f003a61adcb6576364db95d0656b39584157fe7ea37eaae6a4338f4f5ebf896f15a690c195af89878d76bb160f44d4a831c4f6052729511
|
data/.gitignore
CHANGED
@@ -1,18 +1,32 @@
|
|
1
1
|
*.gem
|
2
2
|
*.rbc
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Documentation cache and generated files:
|
13
|
+
/.yardoc/
|
14
|
+
/_yardoc/
|
15
|
+
/doc/
|
16
|
+
/rdoc/
|
17
|
+
|
18
|
+
## Environment normalisation:
|
19
|
+
/.bundle/
|
20
|
+
/lib/bundler/man/
|
21
|
+
|
22
|
+
# for a library or gem, you might want to ignore these files since the code is
|
23
|
+
# intended to run in multiple environments; otherwise, check them in:
|
6
24
|
Gemfile.lock
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
test/tmp
|
16
|
-
test/version_tmp
|
17
|
-
tmp
|
18
|
-
.DS_Store
|
25
|
+
.ruby-version
|
26
|
+
.ruby-gemset
|
27
|
+
|
28
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
29
|
+
.rvmrc
|
30
|
+
|
31
|
+
# additional stuff
|
32
|
+
.DS_Store
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# runoff
|
2
2
|
## About
|
3
3
|
|
4
|
-
A few years ago I had enough of loosing my Skype chat history every time I reinstalled the operating system, so I decided to write a small application that could export it as plain text files. The application
|
4
|
+
A few years ago I had enough of loosing my Skype chat history every time I reinstalled the operating system, so I decided to write a small application that could export it as plain text files. The application was called SDBR and it was an open source project that I do not maintain anymore. Why? I could say that I lost my interest in it, but the real reason probably is the implementation.
|
5
5
|
|
6
|
-
SDBR
|
6
|
+
SDBR was written in C# using WPF, therefore it ran only on Windows. Moreover, it was a GUI application. Yeah, that's a problem, because you don't need the GUI for this kind of functionality. runoff is a command-line tool, that automates the process of exporting your chat history.
|
7
7
|
|
8
8
|
## Install
|
9
9
|
|
@@ -26,12 +26,18 @@ To export specific chats.
|
|
26
26
|
|
27
27
|
runoff some skype_username
|
28
28
|
|
29
|
-
If you don't want to put files into an archive, use `--no-archive` option
|
29
|
+
If you don't want to put files into an archive, use `--no-archive` option.
|
30
30
|
|
31
31
|
runoff all skype_username --no-archive
|
32
32
|
|
33
33
|
runoff some skype_username --no-archive
|
34
34
|
|
35
|
+
Sometimes you might want to use the exported data in a different app, therefore runoff has an option to export in JSON instead of TXT. You just need to specify an adapter using `-A` option.
|
36
|
+
|
37
|
+
runoff all skype_username -A json
|
38
|
+
|
39
|
+
The resulting JSON file contains an array of objects with 3 keys: `date`, `user` and `message`. Each object represents a single chat record.
|
40
|
+
|
35
41
|
## What else?
|
36
42
|
|
37
43
|
Things to do in the future versions:
|
data/bin/runoff
CHANGED
@@ -1,58 +1,31 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
-
|
5
|
-
require 'commander/import'
|
6
|
-
require 'runoff'
|
7
3
|
require 'colorize'
|
8
4
|
|
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
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
command :some do |c|
|
39
|
-
c.syntax = 'runoff some [SKYPE_USERNAME] [OPTIONS]'
|
40
|
-
c.description = "Export only some chats' history"
|
41
|
-
c.option '-f', '--from FILE', 'Location of the main.db file'
|
42
|
-
c.option '-d', '--destination DIR', 'Location for the exoprted files'
|
43
|
-
c.option '--[no-]archive', 'Indicates whether to create an archive'
|
44
|
-
|
45
|
-
c.action do |args, options|
|
46
|
-
begin
|
47
|
-
puts "Exporting...".colorize :green
|
48
|
-
Runoff::Commands::Some.process args, options
|
49
|
-
puts "Export finished.".colorize :green
|
50
|
-
rescue ArgumentError => e
|
51
|
-
puts e.message.colorize :red
|
52
|
-
rescue Sequel::DatabaseError
|
53
|
-
puts "Error: To use runoff you must make sure that the Skype is not running".colorize :red
|
54
|
-
rescue StandardError => e
|
55
|
-
puts e.message.colorize :red
|
56
|
-
end
|
57
|
-
end
|
5
|
+
require_relative '../lib/runoff/commandline/none'
|
6
|
+
require_relative '../lib/runoff/commandline/all'
|
7
|
+
require_relative '../lib/runoff/commandline/some'
|
8
|
+
|
9
|
+
options = { archive: true, adapter: 'TxtAdapter' }
|
10
|
+
available_commands = {
|
11
|
+
'_none' => Runoff::Commandline::None.new(options),
|
12
|
+
'all' => Runoff::Commandline::All.new(options),
|
13
|
+
'some' => Runoff::Commandline::Some.new(options)
|
14
|
+
}
|
15
|
+
|
16
|
+
available_commands['_none'].parser.order!
|
17
|
+
command = available_commands[ARGV.shift]
|
18
|
+
|
19
|
+
if command
|
20
|
+
command.parser.order!
|
21
|
+
command.parser.parse!
|
22
|
+
|
23
|
+
#begin
|
24
|
+
command.execute ARGV
|
25
|
+
#rescue StandardError => e
|
26
|
+
# warn e.message.colorize :red
|
27
|
+
# puts 'Terminated.'.colorize :yellow
|
28
|
+
#end
|
29
|
+
else
|
30
|
+
puts available_commands['_none'].parser.help
|
58
31
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Runoff
|
2
|
+
module Adapters
|
3
|
+
class Adapter
|
4
|
+
protected
|
5
|
+
|
6
|
+
# Internal: Converts a Unix timestamp to a datetime string.
|
7
|
+
#
|
8
|
+
# timestamp - An integer with a Unix timestamp value.
|
9
|
+
#
|
10
|
+
# Examples
|
11
|
+
#
|
12
|
+
# format_timestamp 1397852412
|
13
|
+
# # => "2014-18-04 20:20:12"
|
14
|
+
#
|
15
|
+
# Returns a datetime string in a format of YYY-DD-MM HH:MM::SS
|
16
|
+
def format_timestamp(timestamp)
|
17
|
+
Time.at(timestamp).strftime '%Y-%m-%d %H:%M:%S'
|
18
|
+
end
|
19
|
+
|
20
|
+
# Internal: Skip.
|
21
|
+
def format_from_dispname(dispname)
|
22
|
+
dispname
|
23
|
+
end
|
24
|
+
|
25
|
+
# Internal: Skip.
|
26
|
+
def format_body_xml(xml_content)
|
27
|
+
xml_content
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Runoff
|
4
|
+
module Adapters
|
5
|
+
class JsonAdapter < Adapter
|
6
|
+
# Public: A format String used to build a single entry.
|
7
|
+
ENTRY_FORMAT = '{ "date": "%s", "user": "%s", "message": %s }'
|
8
|
+
|
9
|
+
# Public: Builds a single entry.
|
10
|
+
#
|
11
|
+
# row - An Array containing a single row of data from the database.
|
12
|
+
#
|
13
|
+
# Examples
|
14
|
+
#
|
15
|
+
# build_entry { chatname: "#first_user/$second_user;d3d86c6b0e3b8320" ... }
|
16
|
+
# # => "{ "date": "2014-04-18 20:20:12", "user": "first_user", "message": "This is a text" }"
|
17
|
+
def build_entry(row)
|
18
|
+
formated_data = []
|
19
|
+
|
20
|
+
# NOTE: The first column in the array is used for the grouping by id and
|
21
|
+
# the second is used for the filename.
|
22
|
+
Runoff::COLUMNS[2..-1].each do |column|
|
23
|
+
formated_data << send("format_#{column}", row[column])
|
24
|
+
end
|
25
|
+
|
26
|
+
ENTRY_FORMAT % formated_data
|
27
|
+
end
|
28
|
+
|
29
|
+
# Public: returns a file name.
|
30
|
+
#
|
31
|
+
# chatname - A String with a Skype chatname
|
32
|
+
#
|
33
|
+
# Examples
|
34
|
+
#
|
35
|
+
# get_file_name "#first_user/$second_user;d3d86c6b0e3b8320"
|
36
|
+
# # => first_user_second_user.json
|
37
|
+
#
|
38
|
+
# Returns a valid file name.
|
39
|
+
def get_file_name(chatname)
|
40
|
+
parse_chatname(chatname) + '.json'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Parses a chatname into a human readable name.
|
44
|
+
#
|
45
|
+
# raw_chatname - A String with a Skype chatname.
|
46
|
+
#
|
47
|
+
# Examples
|
48
|
+
#
|
49
|
+
# parse_chatname "#first_user/$second_user;d3d86c6b0e3b8320"
|
50
|
+
# # => first_user_second_user
|
51
|
+
#
|
52
|
+
# Returns a valid name.
|
53
|
+
def parse_chatname(raw_chatname)
|
54
|
+
pattern = /^#(.*)\/\$(.*);.*$/
|
55
|
+
parts = raw_chatname.match(pattern).captures
|
56
|
+
|
57
|
+
parts.reject(&:empty?).join('_')
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: Formats the provided data buffer so that it could be writter to
|
61
|
+
# a JSON file.
|
62
|
+
#
|
63
|
+
# buffer - An Array containing all the chat entries.
|
64
|
+
#
|
65
|
+
# Returns a String
|
66
|
+
def format_file_content(buffer)
|
67
|
+
content = buffer.join(",\n")
|
68
|
+
|
69
|
+
"[#{content}]"
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
# Internal: Escapes the message body so that it could be used in a JSON string
|
75
|
+
#
|
76
|
+
# xml_content - A String containing the chat message
|
77
|
+
#
|
78
|
+
# Examples
|
79
|
+
#
|
80
|
+
# format_body_xml 'foo' # => "\"foo\""
|
81
|
+
#
|
82
|
+
# Returns a String
|
83
|
+
def format_body_xml(xml_content)
|
84
|
+
JSON.generate(xml_content, quirks_mode: true)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Runoff
|
2
|
+
module Adapters
|
3
|
+
class TxtAdapter < Adapter
|
4
|
+
# Public: A format String used to build a single entry.
|
5
|
+
ENTRY_FORMAT = "[%s] %s: %s"
|
6
|
+
|
7
|
+
# Public: Builds a single entry.
|
8
|
+
#
|
9
|
+
# row - An Array containing a single row of data from the database.
|
10
|
+
#
|
11
|
+
# Examples
|
12
|
+
#
|
13
|
+
# build_entry { chatname: "#first_user/$second_user;d3d86c6b0e3b8320" ... }
|
14
|
+
# # => "[2014-04-18 20:20:12] first_user: This is a text"
|
15
|
+
def build_entry(row)
|
16
|
+
formated_data = []
|
17
|
+
|
18
|
+
# NOTE: The first column in the array is used for the grouping by id and
|
19
|
+
# the second is used for the filename.
|
20
|
+
Runoff::COLUMNS[2..-1].each do |column|
|
21
|
+
formated_data << send("format_#{column}", row[column])
|
22
|
+
end
|
23
|
+
|
24
|
+
ENTRY_FORMAT % formated_data
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: returns a file name.
|
28
|
+
#
|
29
|
+
# chatname - A String with a Skype chatname
|
30
|
+
#
|
31
|
+
# Examples
|
32
|
+
#
|
33
|
+
# get_file_name "#first_user/$second_user;d3d86c6b0e3b8320"
|
34
|
+
# # => first_user_second_user.txt
|
35
|
+
#
|
36
|
+
# Returns a valid file name.
|
37
|
+
def get_file_name(chatname)
|
38
|
+
parse_chatname(chatname) + '.txt'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public: Parses a chatname into a human readable name.
|
42
|
+
#
|
43
|
+
# raw_chatname - A String with a Skype chatname.
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# parse_chatname "#first_user/$second_user;d3d86c6b0e3b8320"
|
48
|
+
# # => first_user_second_user
|
49
|
+
#
|
50
|
+
# Returns a valid name.
|
51
|
+
def parse_chatname(raw_chatname)
|
52
|
+
pattern = /^#(.*)\/\$(.*);.*$/
|
53
|
+
parts = raw_chatname.match(pattern).captures
|
54
|
+
|
55
|
+
parts.reject(&:empty?).join('_')
|
56
|
+
end
|
57
|
+
|
58
|
+
# Public: Formats the provided data buffer so that it could be writter to
|
59
|
+
# a text file.
|
60
|
+
#
|
61
|
+
# buffer - An Array containing all the chat entries.
|
62
|
+
#
|
63
|
+
# Returns a String
|
64
|
+
def format_file_content(buffer)
|
65
|
+
buffer.join("\n")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/runoff/chat.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Runoff
|
5
|
+
# Public: Reads data from the SQLite database used by Skype/
|
6
|
+
class Chat
|
7
|
+
|
8
|
+
# Public: Initializes a Chat object.
|
9
|
+
#
|
10
|
+
# db_location - A String with a path to the database file.
|
11
|
+
def initialize(db_location, options)
|
12
|
+
@messages = Sequel.sqlite(db_location)[Runoff::TABLE]
|
13
|
+
@adapter = Object.const_get("Runoff::Adapters::#{options[:adapter]}").new
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Returns a list of all the records in the databse.
|
17
|
+
def get_messages
|
18
|
+
@messages.select(*Runoff::COLUMNS).all.sort_by do |row|
|
19
|
+
[row[Runoff::COLUMNS[0]], row[Runoff::COLUMNS[2]]]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Creates a collection with all chats available for export.
|
24
|
+
#
|
25
|
+
# Returns a Set with hashes e.g. [{ id: 12, name: "chatname" }, ... ]
|
26
|
+
def get_chatname_options
|
27
|
+
options = Set.new
|
28
|
+
|
29
|
+
@messages.select(*Runoff::COLUMNS[0..1]).each do |row|
|
30
|
+
readable_name = @adapter.parse_chatname row[Runoff::COLUMNS[1]]
|
31
|
+
|
32
|
+
options << { id: row[Runoff::COLUMNS[0]], name: readable_name }
|
33
|
+
end
|
34
|
+
|
35
|
+
options
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'command'
|
2
|
+
|
3
|
+
module Runoff
|
4
|
+
# Public: Command classes used by the executable.
|
5
|
+
module Commandline
|
6
|
+
# Public: A command class that is used to export all chat history.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# command = All.new { archive: true }
|
11
|
+
# command.execute [ 'skype_username' ]
|
12
|
+
class All < Command
|
13
|
+
# Public: initialize a new All command object.
|
14
|
+
#
|
15
|
+
# options - A Hash of commandline options (default { archive: true, adapter: 'TxtAdapter' }).
|
16
|
+
def initialize(options = {})
|
17
|
+
@options = options
|
18
|
+
@parser = OptionParser.new do |opts|
|
19
|
+
opts.banner = 'Exports all chats: runoff all [SKYPE_USERNAME] [OPTIONS]'
|
20
|
+
opts.on '-h', '--help', 'Displays help' do
|
21
|
+
puts opts
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on '-f', '--from PATH', 'Specifies the location of the database file (main.db)' do |path|
|
26
|
+
@options[:from] = path
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on '-d', '--destination PATH', 'Changes the default path for the exported files' do |path|
|
30
|
+
@options[:destination] = path
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on '-a', '--[no-]archive', 'Toggles archiving feature' do |enable|
|
34
|
+
@options[:archive] = enable
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on '-A', '--adapter [NAME]', 'Uses a specific file type adapter' do |adapter|
|
38
|
+
@options[:adapter] = adapter.capitalize + 'Adapter'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: executes the command.
|
44
|
+
#
|
45
|
+
# args - An Array of commandline arguments.
|
46
|
+
def execute(args)
|
47
|
+
super args do |chat, file_writer|
|
48
|
+
file_writer.write chat.get_messages
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'colorize'
|
3
|
+
|
4
|
+
require_relative '../../runoff'
|
5
|
+
|
6
|
+
module Runoff
|
7
|
+
# Public: Command classes used by the executable.
|
8
|
+
module Commandline
|
9
|
+
# Public: A base class for all runoff commands except None.
|
10
|
+
#
|
11
|
+
# Should be used only by inheriting.
|
12
|
+
class Command
|
13
|
+
# Public: Returns an OptionParser object
|
14
|
+
attr_reader :parser
|
15
|
+
|
16
|
+
# Public: executes the command.
|
17
|
+
#
|
18
|
+
# args - An Array of commandline arguments.
|
19
|
+
def execute(args)
|
20
|
+
puts 'Exporting...'.colorize :green
|
21
|
+
|
22
|
+
db_location = Location.get_database_path args, @options
|
23
|
+
chat = Chat.new db_location, @options
|
24
|
+
file_writer = FileWriter.new @options
|
25
|
+
|
26
|
+
yield chat, file_writer if block_given?
|
27
|
+
|
28
|
+
file_writer.archive if @options[:archive]
|
29
|
+
|
30
|
+
puts 'Finished.'.colorize :green
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require_relative '../../runoff.rb'
|
3
|
+
|
4
|
+
module Runoff
|
5
|
+
# Public: Command classes used by the executable.
|
6
|
+
module Commandline
|
7
|
+
# Public: The default class that is used when the executable is called
|
8
|
+
# without any commands.
|
9
|
+
#
|
10
|
+
# Examples
|
11
|
+
#
|
12
|
+
# command = None.new { archive: false }
|
13
|
+
class None
|
14
|
+
# Public: Returns an OptionParser object
|
15
|
+
attr_reader :parser
|
16
|
+
|
17
|
+
# Public: initialize a new None command object.
|
18
|
+
#
|
19
|
+
# options - A Hash of commandline options (default { archive: false }).
|
20
|
+
def initialize(options = {})
|
21
|
+
@option = options
|
22
|
+
@parser = OptionParser.new do |opts|
|
23
|
+
opts.banner = <<END
|
24
|
+
runoff - a simple application to create Skype backups
|
25
|
+
|
26
|
+
Usage:
|
27
|
+
|
28
|
+
runoff <COMMAND> [SKYPE_USERNAME] [OPTIONS]
|
29
|
+
|
30
|
+
END
|
31
|
+
|
32
|
+
opts.on '-h', '--help', 'Displays help' do
|
33
|
+
puts opts
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on '-v', '--version', 'Displays a version number' do
|
38
|
+
puts Runoff::VERSION
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative 'command'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
module Runoff
|
5
|
+
# Public: Command classes used by the executable.
|
6
|
+
module Commandline
|
7
|
+
# Public: A command class that is used to export specified chat history.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# command = Some.new { archive: true }
|
12
|
+
# command.execute [ 'skype_username' ]
|
13
|
+
class Some < Command
|
14
|
+
# Public: initialize a new All command object.
|
15
|
+
#
|
16
|
+
# options - A Hash of commandline options (default { archive: true }).
|
17
|
+
def initialize(options = {})
|
18
|
+
@options = options
|
19
|
+
@parser = OptionParser.new do |opts|
|
20
|
+
opts.banner = 'Exports specified chats: runoff some [SKYPE_USERNAME] [OPTIONS]'
|
21
|
+
opts.on '-h', '--help', 'Displays help' do
|
22
|
+
puts opts
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on '-f', '--from PATH', 'Specifies the location of the database file (main.db)' do |path|
|
27
|
+
@options[:from] = path
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on '-d', '--destination PATH', 'Changes the default path for the exported files' do |path|
|
31
|
+
@options[:destination] = path
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on '-a', '--[no-]archive', 'Toggles archiving feature' do |enable|
|
35
|
+
@options[:archive] = enable
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on '-A', '--adapter [NAME]', 'Uses a specific file type adapter' do |adapter|
|
39
|
+
@options[:adapter] = adapter.capitalize + 'Adapter'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: executes the command.
|
45
|
+
#
|
46
|
+
# args - An Array of commandline arguments.
|
47
|
+
def execute(args)
|
48
|
+
super args do |chat, file_writer|
|
49
|
+
ids = prompt_for_chatnames chat
|
50
|
+
messages = chat.get_messages
|
51
|
+
|
52
|
+
selected_messages = messages.keep_if { |m| ids.include? m[Runoff::COLUMNS[0]] }
|
53
|
+
|
54
|
+
file_writer.write selected_messages
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Public: Asks user to specify, which chats to export.
|
59
|
+
#
|
60
|
+
# chat - A Chat object.
|
61
|
+
#
|
62
|
+
# Examples
|
63
|
+
#
|
64
|
+
# get_requested_chatnames Chat.new('/path/to/main.db')
|
65
|
+
# # => [120, 86, 201]
|
66
|
+
#
|
67
|
+
# Returns an Array of conversation ids.
|
68
|
+
def prompt_for_chatnames(chat)
|
69
|
+
puts 'Specify numbers of the chats that you want to export (e.g., 201, 86, 120)'
|
70
|
+
puts
|
71
|
+
|
72
|
+
chat.get_chatname_options.each do |opt|
|
73
|
+
puts "[#{opt[:id]}] #{opt[:name]}"
|
74
|
+
end
|
75
|
+
|
76
|
+
puts
|
77
|
+
print "Numbers: "
|
78
|
+
options = STDIN.gets # NOTE: For some reason just gets throws an error here.
|
79
|
+
|
80
|
+
options.split(',').map(&:to_i)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|