doxieland 0.1.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/doxieland.gemspec +5 -2
- data/exe/doxieland +198 -15
- data/lib/doxieland.rb +26 -2
- data/lib/doxieland/actions/delete_scans.rb +17 -0
- data/lib/doxieland/actions/get_info.rb +8 -0
- data/lib/doxieland/actions/get_scan.rb +20 -0
- data/lib/doxieland/actions/list_scans.rb +16 -0
- data/lib/doxieland/api.rb +3 -1
- data/lib/doxieland/client.rb +94 -0
- data/lib/doxieland/handlers/file_request.rb +43 -0
- data/lib/doxieland/logger.rb +47 -0
- data/lib/doxieland/scan.rb +101 -0
- data/lib/doxieland/version.rb +1 -1
- metadata +59 -11
- data/doxieland.sublime-project +0 -8
- data/doxieland.sublime-workspace +0 -1729
- data/lib/doxieland/handlers/json.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a8265c8aef3acb73110d4c084c45ee809391bb6
|
4
|
+
data.tar.gz: a6636e435c48b7a47fc0035a3d08635083b44c9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbc20ab3361ffadbc3d710b9a8c4e8d384470de16d3b86c6db1926d6542dc67aa2314e24f78de9c0bf51be927e0c81c332c8087c87089b86029d5f55e54276cf
|
7
|
+
data.tar.gz: f3128eb67754c15858636561f8b1588dd76271ca06414ab0a2a8ef39c03ee00a43a6c5293d4e34d343228666e26e92f813b9a757f2a1502899c6fdc06032f4d0
|
data/.gitignore
CHANGED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
doxieland
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.3.0
|
data/doxieland.gemspec
CHANGED
@@ -20,8 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_runtime_dependency 'activesupport', '>= 4.2'
|
23
|
-
spec.add_runtime_dependency 'apidiesel', '>= 0.
|
24
|
-
spec.add_runtime_dependency '
|
23
|
+
spec.add_runtime_dependency 'apidiesel', '>= 0.12'
|
24
|
+
spec.add_runtime_dependency 'thor', '>= 0.19'
|
25
|
+
spec.add_runtime_dependency 'ruby-progressbar', '>= 1.7'
|
26
|
+
spec.add_runtime_dependency 'hirb', '>= 0.7'
|
27
|
+
spec.add_runtime_dependency 'rainbow', '>= 2.1'
|
25
28
|
|
26
29
|
spec.add_development_dependency "bundler", "~> 1.11"
|
27
30
|
spec.add_development_dependency "rake", "~> 10.0"
|
data/exe/doxieland
CHANGED
@@ -1,23 +1,206 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
require "doxieland"
|
4
|
-
require
|
3
|
+
require "thor"
|
4
|
+
require "ruby-progressbar"
|
5
|
+
require 'hirb'
|
6
|
+
|
7
|
+
class CLI < Thor
|
8
|
+
include Thor::Actions
|
5
9
|
|
6
|
-
|
7
|
-
|
8
|
-
program :description, 'A command line tool for downloading scans from the doxie go wi-fi'
|
10
|
+
class_option 'scanner-ip', desc:'your scanners network address', banner: 'xxx.xxx.xxx.xxx', type: :string, aliases: '-i'
|
11
|
+
class_option :password, desc:'your scanners password', type: :string, aliases: '-p'
|
9
12
|
|
10
|
-
|
13
|
+
def initialize(*args, **kargs)
|
14
|
+
super
|
15
|
+
|
16
|
+
@config = (options || HashWithIndifferentAccess.new).reverse_merge(Doxieland.config)
|
17
|
+
@client = Doxieland::Client.new(@config)
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "info", "show information about your scanner"
|
21
|
+
def info
|
22
|
+
response =
|
23
|
+
@client.api do |api|
|
24
|
+
api.get_info.result
|
25
|
+
end
|
26
|
+
|
27
|
+
puts Hirb::Helpers::AutoTable.render(
|
28
|
+
response,
|
29
|
+
description: false,
|
30
|
+
headers: false
|
31
|
+
)
|
32
|
+
end
|
11
33
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
c.action do |args, options|
|
16
|
-
Doxieland::Api.url "http://#{@ip}:8080"
|
17
|
-
api = Doxieland::Api.new
|
34
|
+
desc "list", "list all scans saved in your scanners memory"
|
35
|
+
def list
|
36
|
+
scans = @client.api { |api| api.list_scans.result }
|
18
37
|
|
19
|
-
|
20
|
-
|
38
|
+
if scans.none?
|
39
|
+
log.info "no scans found"
|
40
|
+
exit
|
21
41
|
end
|
42
|
+
|
43
|
+
puts Hirb::Helpers::AutoTable.render(
|
44
|
+
scans,
|
45
|
+
fields: [:name, :path],
|
46
|
+
description: false
|
47
|
+
)
|
48
|
+
|
49
|
+
log.info "#{scans.length} scans available"
|
22
50
|
end
|
23
|
-
|
51
|
+
|
52
|
+
desc "download", <<-EOT.strip_heredoc
|
53
|
+
download all scans from your scanner to your computer
|
54
|
+
|
55
|
+
Available placeholders for filename format strings:
|
56
|
+
%{number} - the image number
|
57
|
+
%{date} - the current date as DD.MM.YYYY
|
58
|
+
%{time} - the current time as HH:MM:SS
|
59
|
+
|
60
|
+
You can further format date and time by passing format options inside the placeholders, separated by a colon:
|
61
|
+
|
62
|
+
%{date:%Y-%m-%d}
|
63
|
+
|
64
|
+
See http://ruby-doc.org/core-2.2.0/Time.html#method-i-strftime for all available date and time formatting options.
|
65
|
+
|
66
|
+
EOT
|
67
|
+
method_option :to, desc: "the directory to save the scans to. Defaults to .", type: :string, aliases: '-t'
|
68
|
+
method_option :filenames,
|
69
|
+
type: :string,
|
70
|
+
aliases: '-f',
|
71
|
+
banner: '"FORMAT_STRING"',
|
72
|
+
desc: 'filename format string. Default: "doxie_scan_%{date}-%{number}"'
|
73
|
+
method_option :pdf, desc: "convert scans to PDF. Requires ImageMagick to be installed", type: :boolean
|
74
|
+
method_option :delete, desc: "delete scans from scanner after download", type: :boolean, aliases: '-d'
|
75
|
+
def download
|
76
|
+
if @config[:pdf]
|
77
|
+
unless command_available?('convert')
|
78
|
+
log.fatal "could not find the 'convert' command. PDF conversion requires ImageMagick to be installed"
|
79
|
+
exit(false)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
@client.create_save_path
|
84
|
+
|
85
|
+
Doxieland::Scan.save_path = @client.save_path
|
86
|
+
Doxieland::Scan.name_format = @config[:filenames] if @config[:filenames]
|
87
|
+
|
88
|
+
scans = @client.api do |api|
|
89
|
+
api.list_scans.result
|
90
|
+
end
|
91
|
+
|
92
|
+
if scans.none?
|
93
|
+
log.info "0 scans available for download on scanner"
|
94
|
+
exit
|
95
|
+
end
|
96
|
+
|
97
|
+
log.info "downloading #{scans.length} scans to " + Rainbow(@client.save_path).cyan.bright
|
98
|
+
|
99
|
+
progressbar = create_progressbar(starting_at: 0, total: scans.length)
|
100
|
+
|
101
|
+
deletable_paths = []
|
102
|
+
save_count = 0
|
103
|
+
|
104
|
+
scans.each do |remote_scan|
|
105
|
+
progressbar.title = "downloading #{remote_scan[:name]}".truncate(22).ljust(25)
|
106
|
+
|
107
|
+
scan = @client.api { |api| api.get_scan(path: remote_scan[:path]).result }
|
108
|
+
|
109
|
+
if @config[:pdf]
|
110
|
+
scan.file_type = 'pdf'
|
111
|
+
progressbar.title = "saving #{remote_scan[:name]} as PDF".truncate(22).ljust(25)
|
112
|
+
else
|
113
|
+
progressbar.title = "saving #{remote_scan[:name]}".truncate(22).ljust(25)
|
114
|
+
end
|
115
|
+
|
116
|
+
if scan.save
|
117
|
+
save_count += 1
|
118
|
+
deletable_paths << remote_scan[:delete_path]
|
119
|
+
else
|
120
|
+
log.progress_warn "skipped existing file #{scan.path}", progressbar
|
121
|
+
end
|
122
|
+
|
123
|
+
progressbar.increment
|
124
|
+
end
|
125
|
+
|
126
|
+
if options[:delete] && deletable_paths.any?
|
127
|
+
progressbar = create_progressbar(title: "deleting scans".ljust(20))
|
128
|
+
|
129
|
+
@client.api { |api| api.delete_scans(paths: deletable_paths).result }
|
130
|
+
|
131
|
+
progressbar.progress = 1
|
132
|
+
progressbar.total = 1
|
133
|
+
progressbar.finish
|
134
|
+
end
|
135
|
+
|
136
|
+
log.success "#{save_count} scans downloaded"
|
137
|
+
end
|
138
|
+
|
139
|
+
desc "defaults", "show or set default options for doxieland"
|
140
|
+
method_option :to, desc: "the directory to save the scans to. Defaults to .", type: :string, aliases: '-t'
|
141
|
+
method_option :filenames,
|
142
|
+
type: :string,
|
143
|
+
aliases: '-f',
|
144
|
+
banner: '"FORMAT_STRING"'
|
145
|
+
method_option :pdf, desc: "convert scans to PDF. Requires ImageMagick to be installed", type: :boolean
|
146
|
+
method_option :delete, desc: "delete scans from scanner after download", type: :boolean, aliases: '-d'
|
147
|
+
def defaults
|
148
|
+
if options.none?
|
149
|
+
config = Doxieland.config
|
150
|
+
|
151
|
+
if config.any?
|
152
|
+
puts Hirb::Helpers::AutoTable.render(
|
153
|
+
config,
|
154
|
+
description: false,
|
155
|
+
headers: { 0 => 'option', 1 => 'value' }
|
156
|
+
)
|
157
|
+
else
|
158
|
+
log.info "no defaults set"
|
159
|
+
end
|
160
|
+
|
161
|
+
else
|
162
|
+
File.open(Doxieland.config_path, 'w') { |file| file << YAML.dump(options) }
|
163
|
+
|
164
|
+
puts Hirb::Helpers::AutoTable.render(
|
165
|
+
config,
|
166
|
+
description: false,
|
167
|
+
headers: { 0 => 'option', 1 => 'value' }
|
168
|
+
)
|
169
|
+
|
170
|
+
log.success "new default settings saved"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
desc "console", "starts a Pry REPL session", hide: true
|
175
|
+
def console
|
176
|
+
begin
|
177
|
+
require 'pry'
|
178
|
+
rescue LoadError
|
179
|
+
log.fatal "doxieland console requires Pry to be installed: gem install pry"
|
180
|
+
exit
|
181
|
+
end
|
182
|
+
binding.pry
|
183
|
+
end
|
184
|
+
|
185
|
+
no_commands do
|
186
|
+
def log
|
187
|
+
@client.log
|
188
|
+
end
|
189
|
+
|
190
|
+
def create_progressbar(**kargs)
|
191
|
+
kargs.reverse_merge!({
|
192
|
+
total: nil,
|
193
|
+
format: "%t (%c of %C) |%b\u{1F431}%i| %E",
|
194
|
+
progress_mark: "\u{2728}",
|
195
|
+
remainder_mark: " ", title: ' ' * 25
|
196
|
+
})
|
197
|
+
ProgressBar.create(**kargs)
|
198
|
+
end
|
199
|
+
|
200
|
+
def command_available?(command)
|
201
|
+
`which #{command}`.present? && $?.exitstatus == 0
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
CLI.start( ARGV.any? ? ARGV : ['help'] )
|
data/lib/doxieland.rb
CHANGED
@@ -2,11 +2,35 @@ require "doxieland/version"
|
|
2
2
|
|
3
3
|
require 'active_support/all'
|
4
4
|
require 'apidiesel'
|
5
|
+
require 'rainbow'
|
6
|
+
require 'open-uri'
|
7
|
+
require 'cgi'
|
8
|
+
require 'pathname'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'open3'
|
5
11
|
|
6
|
-
require 'doxieland/handlers/
|
12
|
+
require 'doxieland/handlers/file_request'
|
7
13
|
require 'doxieland/actions/list_scans'
|
14
|
+
require 'doxieland/actions/get_info'
|
15
|
+
require 'doxieland/actions/get_scan'
|
16
|
+
require 'doxieland/actions/delete_scans'
|
8
17
|
require 'doxieland/api'
|
18
|
+
require 'doxieland/scan'
|
19
|
+
require 'doxieland/logger'
|
20
|
+
require 'doxieland/client'
|
9
21
|
|
10
22
|
module Doxieland
|
11
|
-
|
23
|
+
class AuthenticationError < StandardError; end
|
24
|
+
|
25
|
+
def self.config_path
|
26
|
+
Pathname.new('~/.doxieland').expand_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.config
|
30
|
+
if File.file?(config_path)
|
31
|
+
YAML.load( File.read(config_path) ).with_indifferent_access
|
32
|
+
else
|
33
|
+
HashWithIndifferentAccess.new
|
34
|
+
end
|
35
|
+
end
|
12
36
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Doxieland
|
2
|
+
module Actions
|
3
|
+
class DeleteScans < ::Apidiesel::Action
|
4
|
+
url path: '/scans/delete.json'
|
5
|
+
|
6
|
+
http_method :post
|
7
|
+
|
8
|
+
expects do
|
9
|
+
object :paths, klass: Array
|
10
|
+
end
|
11
|
+
|
12
|
+
format_parameters do |params|
|
13
|
+
params[:paths]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Doxieland
|
2
|
+
module Actions
|
3
|
+
class GetScan < ::Apidiesel::Action
|
4
|
+
use Apidiesel::Handlers::ActionResponseProcessor
|
5
|
+
use Handlers::FileRequest
|
6
|
+
|
7
|
+
url ->(base_url, request) {
|
8
|
+
base_url.path = request.parameters.delete(:path)
|
9
|
+
|
10
|
+
base_url
|
11
|
+
}
|
12
|
+
|
13
|
+
http_method :get
|
14
|
+
|
15
|
+
expects do
|
16
|
+
string :path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -3,6 +3,22 @@ module Doxieland
|
|
3
3
|
class ListScans < ::Apidiesel::Action
|
4
4
|
http_method :get
|
5
5
|
url path: '/scans.json'
|
6
|
+
|
7
|
+
responds_with do
|
8
|
+
array do
|
9
|
+
string :path,
|
10
|
+
at: :name,
|
11
|
+
filter: ->(s) { "/scans#{s}" }
|
12
|
+
string :delete_path,
|
13
|
+
at: :name
|
14
|
+
string :thumbnail_path,
|
15
|
+
at: :name,
|
16
|
+
filter: ->(s) { "/thumbnails#{s}" }
|
17
|
+
string :name,
|
18
|
+
filter: ->(s) { s.match(/[0-9]{4,}/)[0] }
|
19
|
+
integer :size
|
20
|
+
end
|
21
|
+
end
|
6
22
|
end
|
7
23
|
end
|
8
24
|
end
|
data/lib/doxieland/api.rb
CHANGED
@@ -0,0 +1,94 @@
|
|
1
|
+
module Doxieland
|
2
|
+
class Client
|
3
|
+
attr_reader :save_path
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
|
+
@save_path = Pathname.new(options[:to] || '.').expand_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def api(&block)
|
11
|
+
Doxieland::Api.url "http://#{scanner_ip}:8080"
|
12
|
+
|
13
|
+
if @options[:password]
|
14
|
+
Doxieland::Api.http_basic_auth 'doxie', @options[:password]
|
15
|
+
end
|
16
|
+
|
17
|
+
api = Doxieland::Api.new
|
18
|
+
|
19
|
+
begin
|
20
|
+
yield api
|
21
|
+
rescue AuthenticationError => e
|
22
|
+
log.fatal e.message
|
23
|
+
exit(false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_save_path
|
28
|
+
raise ArgumentError, "#{@save_path} is a file" if @save_path.file?
|
29
|
+
|
30
|
+
unless @save_path.directory? || @save_path == Pathname.new('.')
|
31
|
+
FileUtils.mkdir_p(@save_path)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def loglevel
|
36
|
+
@options[:verbose] ? :debug : :info
|
37
|
+
end
|
38
|
+
|
39
|
+
def log
|
40
|
+
@logger ||= Logger.new(loglevel)
|
41
|
+
end
|
42
|
+
|
43
|
+
def scanner_ip
|
44
|
+
@scanner_ip ||= begin
|
45
|
+
if @options['scanner-ip']
|
46
|
+
@options['scanner-ip']
|
47
|
+
elsif @options[:ap]
|
48
|
+
'192.168.1.100'
|
49
|
+
else
|
50
|
+
discovered_ip = ssdp_discover
|
51
|
+
|
52
|
+
unless discovered_ip
|
53
|
+
log.fatal "… sorry, your scanner could not be found. Is WiFi turned on and the status light blue?"
|
54
|
+
log.info "If you know it, you can also provide the IP address manually via the --scanner-ip flag."
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
58
|
+
discovered_ip
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def ssdp_discover
|
64
|
+
socket = UDPSocket.new
|
65
|
+
socket.setsockopt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
|
66
|
+
socket.setsockopt :IPPROTO_IP, :IP_MULTICAST_TTL, 1
|
67
|
+
|
68
|
+
query = [
|
69
|
+
'M-SEARCH * HTTP/1.1',
|
70
|
+
'HOST: 239.255.255.250:1900',
|
71
|
+
'MAN: "ssdp:discover"',
|
72
|
+
'ST: urn:schemas-getdoxie-com:device:Scanner:1',
|
73
|
+
# 'ST: ssdp:all',
|
74
|
+
'MX: 3',
|
75
|
+
'',
|
76
|
+
''
|
77
|
+
].join("\r\n")
|
78
|
+
|
79
|
+
log.info "trying to find your scanner on the network. Here, Doxie Doxie…"
|
80
|
+
|
81
|
+
socket.send(query, 0, '239.255.255.250', 1900)
|
82
|
+
|
83
|
+
ready = IO.select([socket], nil, nil, 10)
|
84
|
+
|
85
|
+
if ready
|
86
|
+
_, message_sender = socket.recvfrom(65507)
|
87
|
+
|
88
|
+
log.success "found the little rascal hiding at #{message_sender.last}"
|
89
|
+
|
90
|
+
message_sender.last
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|