runoff 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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