runoff 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07466177c09c57169067c0d8a59dbc5ad4e4d921
4
- data.tar.gz: 660f59d6d1adfa80f4bd7a9931988ebb446aa7d2
3
+ metadata.gz: 68f134e0964050cf348514719437dde550790071
4
+ data.tar.gz: 23af26df004e1810c9a6b937ca161932eb157ef1
5
5
  SHA512:
6
- metadata.gz: 4f26579401ab7ac73d8a7447a9101c190a4241f5dc1d95cd916542018211139b91eb3613f751eef813a372b74ff4c9b75e4d0cd8c4d6d677451c1d47d0c4677e
7
- data.tar.gz: db956c7fcc9b3abf62149162b2bf68996b93c34d149d0321f9fb04f710df9b435627ee2fc7555ee05e372b4c103864834f450a150d415810d1fd371970c214d4
6
+ metadata.gz: ff8e74e3aab2ec0a04d05c08e9544afc4fffeadf1d479549a45349627aeb200e9db76afb3ef52be5113f06ae1733289928d8f8416efd0c07110e6065d7c85963
7
+ data.tar.gz: f286bd9541f12f7b5b9ab04b2f3e6c2670b8cf27bb15b0c8ef56a979005f717e774bea8473f54f073691b51343d7038e5ef58ca65914ef68cfd164f845f42a0d
data/.gitignore CHANGED
@@ -1,17 +1,17 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
2
-
3
- # gem's dependencies are specified in runoff.gemspec
4
- gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ # gem's dependencies are specified in runoff.gemspec
4
+ gemspec
data/LICENSE.txt CHANGED
@@ -1,22 +1,22 @@
1
- Copyright (c) 2013 Aigars Dzerviniks
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1
+ Copyright (c) 2013 Aigars Dzerviniks
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,45 +1,42 @@
1
- # runoff
2
- ## About
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 is called [SDBR](https://github.com/arvislacis/SDBR) and it is 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
-
6
- SDBR is written in C# using WPF, therefore it runs only on Windows. Moreover, it is a GUI application. Yeah, that's a problem, because you don't need the GUI for this kind of functionality. runoff is a commandline tool, that automates the process of exporting your chat history.
7
-
8
- ## Install
9
-
10
- gem install runoff
11
-
12
- ## Usage
13
-
14
- To export all the chat history.
15
-
16
- # save all the files in your home directory
17
- runoff all skype_username
18
-
19
- # save the files in a specific directory
20
- runoff all skype_username -t ~/skype_backup
21
-
22
- # export database that isn't located in the default path
23
- runoff all -f ~/main.db -t ~/skype_backup
24
-
25
- To export specific chats.
26
-
27
- runoff chat skype_username -t ~/skype_backup
28
-
29
- If you don't want to put files into an archive, use `--no-archive` option
30
-
31
- runoff all skype_username --no-archive
32
-
33
- If you're confused, you can get some help.
34
-
35
- runoff help all
36
-
37
- ## What else?
38
-
39
- Things to do in the future versions:
40
-
41
- - Parse body_xml to filter XML tags and character entities.
42
- - Append only new messages to the previously genetrated files instead of appending everything or create different versions for the files when using `--no-archive option`.
43
- - Add some colors.
44
-
45
- If you have something to say about this gem or anything else, you can find me on Twitter as [@AigarsDz](http://twitter.com/AigarsDz "@AigarsDz").
1
+ # runoff
2
+ ## About
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 is called [SDBR](https://github.com/arvislacis/SDBR) and it is 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
+
6
+ SDBR is written in C# using WPF, therefore it runs only on Windows. Moreover, it is a GUI application. Yeah, that's a problem, because you don't need the GUI for this kind of functionality. runoff is a commandline tool, that automates the process of exporting your chat history.
7
+
8
+ ## Install
9
+
10
+ gem install runoff
11
+
12
+ ## Usage
13
+
14
+ To export all the chat history.
15
+
16
+ # save a Zip archive in your home directory
17
+ runoff all skype_username
18
+
19
+ # save a Zip archive in a specific directory
20
+ runoff all skype_username -d ~/backups
21
+
22
+ # export database that isn't located in the default path
23
+ runoff all -f ~/main.db -d ~/backups
24
+
25
+ To export specific chats.
26
+
27
+ runoff chat skype_username
28
+
29
+ If you don't want to put files into an archive, use `--no-archive` option
30
+
31
+ runoff all skype_username -a false
32
+
33
+ ## What else?
34
+
35
+ Things to do in the future versions:
36
+
37
+ - Refactore tests (move from MiniTest::Spec to MiniTest::Unit).
38
+ - Parse body_xml to filter XML tags and character entities.
39
+ - Append only new messages to the previously genetrated files instead of appending everything or create different versions for the files when using `-a false` option.
40
+ - Add some colors.
41
+
42
+ If you have something to say about this gem or anything else, you can find me on Twitter as [@aigarsdz](http://twitter.com/aigarsdz "@aigarsdz").
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require 'rake/testtask'
3
-
4
- Rake::TestTask.new do |t|
5
- t.libs.push "lib"
6
- t.test_files = FileList['test/*_test.rb']
7
- t.verbose = true
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push "lib"
6
+ t.test_files = FileList['test/*_test.rb']
7
+ t.verbose = true
8
8
  end
data/bin/runoff CHANGED
@@ -1,7 +1,34 @@
1
- #!/usr/bin/env ruby
2
-
3
- $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
-
5
- require 'runoff'
6
-
7
- Runoff::Source.start ARGV
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
+
5
+ require 'commander/import'
6
+ require 'runoff'
7
+
8
+ program :name, 'runoff'
9
+ program :version, Runoff::VERSION
10
+ program :description, 'runoff is a simple application to create Skype backups'
11
+
12
+ default_command :help
13
+
14
+ global_option '-f', '--from FILE', 'Location of the main.db file'
15
+ global_option '-d', '--destination DIR', 'Location for the exoprted files'
16
+ global_option '-a', '--archive', 'Save files in a Zip archive (defaults to true)'
17
+
18
+ command :all do |command|
19
+ command.syntax = 'runoff all [SKYPE_USERNAME] [OPTIONS]'
20
+ command.description = 'Export all chat history'
21
+
22
+ command.action do |args, options|
23
+ Runoff::Commands::All.process args, options.__hash__
24
+ end
25
+ end
26
+
27
+ command :chat do |command|
28
+ command.syntax = 'runoff chat [SKYPE_USERNAME] [OPTIONS]'
29
+ command.description = 'Export pecified chats history'
30
+
31
+ command.action do |args, options|
32
+ Runoff::Commands::Chat.process args, options.__hash__
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module Runoff
2
+ # Public: Commands that can be executed by the application.
3
+ module Commands
4
+ # Public: Command to export all Skype chat history.
5
+ #
6
+ # Examples
7
+ #
8
+ # All.process ['username'], { from: '/path/to/main.db' }
9
+ class All < Command
10
+ # Public: Export all chats.
11
+ #
12
+ # args - Array containing skype username
13
+ # options - Hash containing user provided options
14
+ #
15
+ # Examples
16
+ #
17
+ # All.process ['username'], { from: '~/main.db' }
18
+ def self.process(args, options = {})
19
+ if args.empty? && !options.has_key?(:from)
20
+ raise ArgumentError.new 'You must specify a username or a --from option'
21
+ end
22
+
23
+ composition = self.get_composition args[0], options[:from]
24
+ destination = self.get_destination options[:destination]
25
+
26
+ self.print_result composition.export(destination)
27
+ self.try_to_archive destination, options[:archive]
28
+
29
+ rescue ArgumentError => e
30
+ puts e
31
+ rescue IOError => e
32
+ puts e
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,37 @@
1
+ module Runoff
2
+ module Commands
3
+ class Chat < Command
4
+ # Public: Exports specified chats.
5
+ #
6
+ # args - Array containing skype username
7
+ # options - Hash containing user provided options
8
+ #
9
+ # Examples
10
+ #
11
+ # Chat.process ['username'], { from: '~/main.db' }
12
+ def self.process(args, options = {})
13
+ if args.empty? && !options.has_key?('from')
14
+ raise ArgumentError.new 'You must specify a username or a --from option'
15
+ end
16
+
17
+ composition = self.get_composition args[0], options[:from]
18
+ destination = self.get_destination options[:destination]
19
+ chatnames, raw_chatnames = composition.get_chatnames
20
+
21
+ self.list_chatnames chatnames
22
+ indecies = ask 'Which chats do you want to export? (Enter indecies) ', Array
23
+ indecies = indecies.map { |index| index.to_i }
24
+ selected_chatnames = []
25
+
26
+ indecies.each { |index| selected_chatnames << raw_chatnames[index] }
27
+ self.print_result composition.export_chats(selected_chatnames, destination)
28
+ self.try_to_archive destination, options
29
+
30
+ rescue ArgumentError => e
31
+ puts e
32
+ rescue IOError => e
33
+ puts e
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,85 @@
1
+ module Runoff
2
+ # Public: Commands that can be executed by the application.
3
+ module Commands
4
+ # Public: Methods that are shared between different commands.
5
+ class Command
6
+ private
7
+ # Internal: Gets a Composition object.
8
+ #
9
+ # skype_username - A String that contains a username of the Skype account,
10
+ # which database we want to access.
11
+ # optional_path - A String that contains path to a main.db file (Skype's database).
12
+ #
13
+ # Examples
14
+ #
15
+ # get_composition 'skype_username', ''
16
+ # # => #<Composition:0x00002324212>
17
+ #
18
+ # Returns a Composition object with a reference to a specific Skype database.
19
+ def self.get_composition(skype_username, optional_path)
20
+ Runoff::Composition.new optional_path, skype_username
21
+ end
22
+
23
+ # Internal: Gets a destination path depending on the entered options.
24
+ #
25
+ # optional_path - A String that contains path where to save exported files.
26
+ #
27
+ # Examples
28
+ #
29
+ # get_destination ''
30
+ # # => '~/skype_backup'
31
+ #
32
+ # Returns a String containing a path to the destination directory.
33
+ def self.get_destination(optional_path)
34
+ optional_path || "#{ENV['HOME']}/skype-backup"
35
+ end
36
+
37
+ # Internal: Informs the user that the application has finished running.
38
+ #
39
+ # count - A number of files that have been exported
40
+ #
41
+ # Examples
42
+ #
43
+ # print_result 4
44
+ # # => Finished: 4 files were exported
45
+ def self.print_result(count)
46
+ if count == 1
47
+ puts 'Finished: 1 file was exported'
48
+ elsif count > 1
49
+ puts "Finished: #{count} files were exported"
50
+ end
51
+ end
52
+
53
+ # Internal: Prints available chatnames.
54
+ #
55
+ # chatnames - An Array containing the chatname strings
56
+ #
57
+ # Examples
58
+ #
59
+ # list_chatnames ['something-more', 'something-else']
60
+ # # => [0] something-more
61
+ # [1] something-else
62
+ def self.list_chatnames(chatnames)
63
+ chatnames.each_with_index { |n, i| puts "[#{i}] #{n}" }
64
+ puts
65
+ end
66
+
67
+ # Internal: performs archiving if an --archive option is provided
68
+ #
69
+ # destination - A String containing a path to the export directory.
70
+ # is_archive_enebled - A flag indicating whether to create an archive.
71
+ #
72
+ # Examples
73
+ #
74
+ # try_to_archive '/home/username/skype-backup', { archive: false }
75
+ def self.try_to_archive(destination, is_archive_enebled)
76
+ unless is_archive_enebled
77
+ Runoff::FileWriter.archive destination
78
+ end
79
+ rescue StandardError => e
80
+ puts e
81
+ puts 'Faild to create an archive'
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,103 +1,105 @@
1
- require 'sequel'
2
- require 'set'
3
-
4
- module Runoff
5
- # Public: Provides interaction with a Skype database file.
6
- #
7
- # Examples
8
- #
9
- # composition = Composition.new 'path/to/the/main.db'
10
- # exported_files_count = composition.export 'export/folder'
11
- class Composition
12
- include FileWriter
13
-
14
- # Public: Returns a Set object of all the names of the exported files.
15
- attr_reader :exported_filenames
16
-
17
- # Public: Initialize a Composition object.
18
- #
19
- # main_db_file_path - A String with the path to the Skype database file.
20
- #
21
- # Raises IOError if the file cannot be found
22
- def initialize(main_db_file_path)
23
- raise IOError, "File doesn't exist" unless File.exists? main_db_file_path
24
-
25
- skype_database = Sequel.connect "sqlite://#{main_db_file_path}"
26
- @messages = skype_database.from :Messages
27
- @exported_filenames = Set.new
28
- end
29
-
30
- # Public: Exports Skype chat history to text files.
31
- #
32
- # destination_path - A String with folder path, where to put exported files.
33
- #
34
- # Examples
35
- #
36
- # export '/home/username/skype_backup'
37
- # # => 8
38
- #
39
- # Returns the count of the exported files.
40
- def export(destination_path)
41
- chat_records = @messages.select(:chatname, :timestamp, :from_dispname, :body_xml)
42
-
43
- run_export chat_records, destination_path
44
- end
45
-
46
- # Public: Gets parsed chatnames together with partly parsed chatnames.
47
- #
48
- # Examples
49
- #
50
- # get_chatnames
51
- # # => [['something-more', 'somethindg-else'],
52
- # ['#something/$more;6521032', '#something/$else;8971263']]
53
- #
54
- # Returns two Array objects containing parsed chatnames and partly parsed chatnames.
55
- def get_chatnames
56
- chatnames = @messages.select(:chatname)
57
- raw_chatnames = chatnames.map { |record| partly_parse_chatname record[:chatname] }.uniq
58
- clean_chatnames = raw_chatnames.map { |chatname| parse_chatname chatname }
59
-
60
- return clean_chatnames, raw_chatnames
61
- end
62
-
63
- # Public: Exports Skype chat history to text files for specified chats.
64
- #
65
- # chatnames - Array of chatnames, which will be exported
66
- # destination_path - A String with folder path, where to put exported files.
67
- #
68
- # Examples
69
- #
70
- # export_chats ['#something/$more;', '#something/$else;'], '~/skype_backup'
71
- # # => 2
72
- #
73
- # Returns the count of the exported files.
74
- def export_chats(chatnames, destination_path)
75
- pattern_chatnames = chatnames.map { |name| "#{name}%" }
76
- chat_records = @messages.where(Sequel.like(:chatname, *pattern_chatnames))
77
-
78
- run_export chat_records, destination_path
79
- end
80
-
81
- private
82
-
83
- # Internal: Performs the export process.
84
- #
85
- # chat_records - Array of chat records read from database
86
- #
87
- # Examples
88
- #
89
- # run_export [{chatname: '#sadsad/$kjhkjh;9878977', 123123213, 'Aidzis', ''}]
90
- # # => 1
91
- #
92
- # Returns the count of the exported files.
93
- def run_export(chat_records, destination_path)
94
- chat_records.each do |record|
95
- if filename = save_to_file(record, destination_path)
96
- @exported_filenames << filename
97
- end
98
- end
99
-
100
- @exported_filenames.count
101
- end
102
- end
103
- end
1
+ require 'sequel'
2
+ require 'set'
3
+
4
+ module Runoff
5
+ # Public: Provides interaction with a Skype database file.
6
+ #
7
+ # Examples
8
+ #
9
+ # composition = Composition.new 'path/to/the/main.db'
10
+ # exported_files_count = composition.export 'export/folder'
11
+ class Composition
12
+ # Public: Returns a Set object of all the names of the exported files.
13
+ attr_reader :exported_filenames
14
+
15
+ # Public: Initialize a Composition object.
16
+ #
17
+ # main_db_file_path - A String with the path to the Skype database file.
18
+ # skype_username - A String with Skype login.
19
+ #
20
+ # Raises IOError if the file cannot be found
21
+ def initialize(optional_file_path, skype_username = nil)
22
+ main_db_file_path = optional_file_path || Runoff::Location.default_skype_data_location(skype_username)
23
+
24
+ raise IOError, "File doesn't exist" unless File.exists? main_db_file_path
25
+
26
+ skype_database = Sequel.connect "sqlite://#{main_db_file_path}"
27
+ @messages = skype_database.from :Messages
28
+ @exported_filenames = Set.new
29
+ @format = Runoff::SkypeDataFormat.new
30
+ @file_writer = Runoff::FileWriter.new @format
31
+ end
32
+
33
+ # Public: Reads all chat records from database and runs the export process.
34
+ #
35
+ # destination_path - A String with folder path, where to put exported files.
36
+ #
37
+ # Examples
38
+ #
39
+ # export '/home/username/skype_backup'
40
+ # # => 8
41
+ #
42
+ # Returns the count of the exported files.
43
+ def export(destination_path)
44
+ chat_records = @messages.select(:chatname, :timestamp, :from_dispname, :body_xml)
45
+
46
+ run_export chat_records, destination_path
47
+ end
48
+
49
+ # Public: Gets parsed chatnames together with partly parsed chatnames.
50
+ #
51
+ # Examples
52
+ #
53
+ # get_chatnames
54
+ # # => [['something-more', 'somethindg-else'],
55
+ # ['#something/$more;6521032', '#something/$else;8971263']]
56
+ #
57
+ # Returns two Array objects containing parsed chatnames and partly parsed chatnames.
58
+ def get_chatnames
59
+ chatnames = @messages.select(:chatname)
60
+ raw_chatnames = chatnames.map { |record| @format.partly_parse_chatname record[:chatname] }.uniq
61
+ clean_chatnames = raw_chatnames.map { |chatname| @format.parse_chatname chatname }
62
+
63
+ return clean_chatnames, raw_chatnames
64
+ end
65
+
66
+ # Public: Exports Skype chat history to text files for specified chats.
67
+ #
68
+ # chatnames - Array of chatnames, which will be exported
69
+ # destination_path - A String with folder path, where to put exported files.
70
+ #
71
+ # Examples
72
+ #
73
+ # export_chats ['#something/$more;', '#something/$else;'], '~/skype_backup'
74
+ # # => 2
75
+ #
76
+ # Returns the count of the exported files.
77
+ def export_chats(chatnames, destination_path)
78
+ pattern_chatnames = chatnames.map { |name| "#{name}%" }
79
+ chat_records = @messages.where(Sequel.like(:chatname, *pattern_chatnames))
80
+
81
+ run_export chat_records, destination_path
82
+ end
83
+
84
+ private
85
+ # Internal: Performs the export process.
86
+ #
87
+ # chat_records - Array of chat records read from database
88
+ #
89
+ # Examples
90
+ #
91
+ # run_export [{chatname: '#sadsad/$kjhkjh;9878977', 123123213, 'Aidzis', ''}]
92
+ # # => 1
93
+ #
94
+ # Returns the count of the exported files.
95
+ def run_export(chat_records, destination_path)
96
+ chat_records.each do |record|
97
+ if filename = @file_writer.save_to_file(record, destination_path)
98
+ @exported_filenames << filename
99
+ end
100
+ end
101
+
102
+ @exported_filenames.count
103
+ end
104
+ end
105
+ end