edango 0.5.1
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.
- data/Copying.txt +679 -0
- data/History.txt +6 -0
- data/Manifest.txt +46 -0
- data/PostInstall.txt +6 -0
- data/README.rdoc +117 -0
- data/Rakefile +21 -0
- data/bin/edango +34 -0
- data/lib/edango.rb +42 -0
- data/lib/edango/context.rb +23 -0
- data/lib/edango/context/directories.rb +67 -0
- data/lib/edango/context/files.rb +37 -0
- data/lib/edango/context/language.rb +101 -0
- data/lib/edango/context/parameters.rb +44 -0
- data/lib/edango/context/services.rb +147 -0
- data/lib/edango/di/container.rb +160 -0
- data/lib/edango/di/helpers.rb +41 -0
- data/lib/edango/di/proxy.rb +54 -0
- data/lib/edango/di/service.rb +60 -0
- data/lib/edango/di/service_factory.rb +40 -0
- data/lib/edango/environment.rb +77 -0
- data/lib/edango/executor.rb +64 -0
- data/lib/edango/helpers/hash.rb +30 -0
- data/lib/edango/helpers/kernel.rb +41 -0
- data/lib/edango/helpers/object.rb +65 -0
- data/lib/edango/helpers/string.rb +29 -0
- data/lib/edango/helpers/symbol.rb +39 -0
- data/lib/edango/logic/ticket_extractor.rb +258 -0
- data/lib/edango/site/core.rb +182 -0
- data/lib/edango/site/public/favicon.ico +0 -0
- data/lib/edango/site/public/images/btn-back-help.png +0 -0
- data/lib/edango/site/public/images/bullet.png +0 -0
- data/lib/edango/site/public/images/ctrl-back.gif +0 -0
- data/lib/edango/site/public/images/frm-back-err.png +0 -0
- data/lib/edango/site/public/images/frm-back-help.png +0 -0
- data/lib/edango/site/public/images/frm-back.png +0 -0
- data/lib/edango/site/public/images/logo.png +0 -0
- data/lib/edango/site/public/scripts/jquery.js +4376 -0
- data/lib/edango/site/public/scripts/jquery.min.js +19 -0
- data/lib/edango/site/public/scripts/logic.js +6 -0
- data/lib/edango/site/public/styles/layout.css +270 -0
- data/lib/edango/site/views/errors.haml +12 -0
- data/lib/edango/site/views/help.haml +10 -0
- data/lib/edango/site/views/index.haml +27 -0
- data/lib/edango/site/views/layout.haml +15 -0
- data/lib/edango/site/views/result.haml +10 -0
- data/lib/edango/starter.rb +141 -0
- metadata +162 -0
@@ -0,0 +1,258 @@
|
|
1
|
+
# EDango - torrent ticket extractor.
|
2
|
+
# Copyright (C) 2010 Dmitrii Toksaitov
|
3
|
+
#
|
4
|
+
# This file is part of EDango.
|
5
|
+
#
|
6
|
+
# EDango is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# EDango is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with EDango. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module EDango
|
20
|
+
|
21
|
+
class TicketExtractor
|
22
|
+
attr_reader :errors
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@environment = SERVICES[:environment]
|
26
|
+
@options = @environment.options
|
27
|
+
|
28
|
+
@timer = SERVICES[:timer]
|
29
|
+
@time_limit = @options[:time_limit]
|
30
|
+
|
31
|
+
@errors = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def extract_tickets(url, passkey, specs)
|
35
|
+
result = []
|
36
|
+
|
37
|
+
@errors = []
|
38
|
+
@agent = SERVICES[:agent, :init]
|
39
|
+
|
40
|
+
specs.each do |spec|
|
41
|
+
errors_root = @errors
|
42
|
+
|
43
|
+
@errors << [spec.first]
|
44
|
+
@errors = @errors.last
|
45
|
+
|
46
|
+
begin
|
47
|
+
@timer.timeout(@time_limit) do
|
48
|
+
result += extract_ticket(url, passkey, spec)
|
49
|
+
end
|
50
|
+
rescue Timeout::Error => e
|
51
|
+
@errors << t(:operation_timed_out)
|
52
|
+
end
|
53
|
+
|
54
|
+
@errors = errors_root
|
55
|
+
@errors.pop() if @errors.last.size == 1
|
56
|
+
end
|
57
|
+
|
58
|
+
if specs.empty?
|
59
|
+
@errors.unshift([t(:all_specs), t(:no_specs_for_url)])
|
60
|
+
end
|
61
|
+
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def extract_ticket(target_url, passkey, specs)
|
67
|
+
result = []
|
68
|
+
|
69
|
+
specs = check_specs(specs)
|
70
|
+
|
71
|
+
ticket_link_regex = specs[0]
|
72
|
+
source_passkey = specs[1]
|
73
|
+
|
74
|
+
login, password = specs[2]
|
75
|
+
|
76
|
+
login_url = specs[3]
|
77
|
+
|
78
|
+
valid? login(login_url, target_url, login, password) do
|
79
|
+
ticket_link = find_ticket_link(target_url, ticket_link_regex)
|
80
|
+
|
81
|
+
raw_ticket = save_raw_ticket(ticket_link)
|
82
|
+
ticket = process_ticket(raw_ticket, source_passkey, passkey)
|
83
|
+
|
84
|
+
result << ticket if ticket
|
85
|
+
end
|
86
|
+
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
def check_specs(specs)
|
91
|
+
ticket_link_regex = check_spec(specs[1], :ticket_link_regex)
|
92
|
+
passkey = check_spec(specs[2], :source_passkey)
|
93
|
+
|
94
|
+
login, password = specs[3]
|
95
|
+
|
96
|
+
login_url = check_spec(specs[4], :login_url)
|
97
|
+
|
98
|
+
[ticket_link_regex, passkey, [login, password], login_url]
|
99
|
+
end
|
100
|
+
|
101
|
+
def check_spec(spec, error_key)
|
102
|
+
result = spec
|
103
|
+
|
104
|
+
if spec.nil_or_empty?
|
105
|
+
@errors << t("empty_#{error_key}".intern())
|
106
|
+
result = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
def login(login_url, target_url, login, password)
|
113
|
+
result = false
|
114
|
+
|
115
|
+
if login_url and not login or not password
|
116
|
+
@errors << t(:empty_login) unless login
|
117
|
+
@errors << t(:empty_password) unless password
|
118
|
+
|
119
|
+
login_url = nil
|
120
|
+
elsif not login_url and login and password
|
121
|
+
login_url = target_url
|
122
|
+
end
|
123
|
+
|
124
|
+
if login_url
|
125
|
+
begin
|
126
|
+
@agent.get(login_url) do |page|
|
127
|
+
form = page.forms.find { |form| form.action =~ /login/ }
|
128
|
+
form.login_username = login
|
129
|
+
form.login_password = password
|
130
|
+
|
131
|
+
login_result = form.click_button()
|
132
|
+
raise() unless login_result
|
133
|
+
end
|
134
|
+
result = true
|
135
|
+
rescue Exception => e
|
136
|
+
@errors << t(:login_process_failed)
|
137
|
+
@environment.log_warning(e.message)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
result
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_ticket_link(url, link_regex)
|
145
|
+
result = nil
|
146
|
+
|
147
|
+
valid? url, link_regex do
|
148
|
+
begin
|
149
|
+
link_regex = Regexp.new(link_regex)
|
150
|
+
|
151
|
+
@agent.get(url) do |page|
|
152
|
+
page.links.each do |link|
|
153
|
+
(result = link; break) if link.href =~ link_regex
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
unless result
|
158
|
+
@errors << t(:ticket_link_not_found)
|
159
|
+
end
|
160
|
+
rescue Exception => e
|
161
|
+
@errors << t(:ticket_page_loading_failed)
|
162
|
+
@environment.log_warning(e.message)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
result
|
167
|
+
end
|
168
|
+
|
169
|
+
def save_raw_ticket(link)
|
170
|
+
result = nil
|
171
|
+
|
172
|
+
if link
|
173
|
+
host = SERVICES[:uri].host(link.page.uri)
|
174
|
+
times = Time.now.strftime('%H-%M-%S_%m.%d.%Y')
|
175
|
+
|
176
|
+
file = "raw_ticket_#{host}_#{times}"
|
177
|
+
file = File.join(DIRS[:tickets], file)
|
178
|
+
|
179
|
+
unique_name = file; number = 1
|
180
|
+
while File.exists?("#{unique_name}.torrent")
|
181
|
+
unique_name = "#{file}_#{number}"
|
182
|
+
number += 1
|
183
|
+
end
|
184
|
+
|
185
|
+
file = "#{unique_name}.torrent"
|
186
|
+
link.click().save_as(file) rescue nil
|
187
|
+
|
188
|
+
unless File.exists?(file)
|
189
|
+
@errors << t(:raw_ticket_not_saved)
|
190
|
+
else
|
191
|
+
result = file
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
result
|
196
|
+
end
|
197
|
+
|
198
|
+
def process_ticket(path, source_passkey, passkey)
|
199
|
+
result = nil
|
200
|
+
|
201
|
+
valid? path, passkey, source_passkey do
|
202
|
+
begin
|
203
|
+
new_path = path.gsub('raw_', '')
|
204
|
+
|
205
|
+
File.open(new_path, 'w+') do |writer|
|
206
|
+
ticket = replace_passkey(read_raw_ticket(path), source_passkey, passkey)
|
207
|
+
writer.binmode.write(ticket) if ticket
|
208
|
+
end
|
209
|
+
|
210
|
+
if File.exists?(new_path)
|
211
|
+
result = new_path
|
212
|
+
else
|
213
|
+
raise()
|
214
|
+
end
|
215
|
+
rescue Exception => e
|
216
|
+
@errors << t(:processed_ticket_not_saved)
|
217
|
+
@environment.log_warning(e.message)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
result
|
222
|
+
end
|
223
|
+
|
224
|
+
def read_raw_ticket(path)
|
225
|
+
result = nil
|
226
|
+
|
227
|
+
begin
|
228
|
+
File.open(path, 'r') do |io|
|
229
|
+
result = io.binmode.read()
|
230
|
+
end
|
231
|
+
rescue Exception => e
|
232
|
+
@errors << t(:raw_ticket_not_opened)
|
233
|
+
@environment.log_warning(e.message)
|
234
|
+
end
|
235
|
+
|
236
|
+
result
|
237
|
+
end
|
238
|
+
|
239
|
+
def replace_passkey(raw_ticket, source_passkey, passkey)
|
240
|
+
result = nil
|
241
|
+
|
242
|
+
if raw_ticket
|
243
|
+
ticket = raw_ticket.gsub(source_passkey, passkey)
|
244
|
+
|
245
|
+
if ticket == raw_ticket
|
246
|
+
if passkey != source_passkey
|
247
|
+
@errors << t(:passkey_not_found)
|
248
|
+
end
|
249
|
+
else
|
250
|
+
result = ticket
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
result
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# EDango - torrent ticket extractor.
|
2
|
+
# Copyright (C) 2010 Dmitrii Toksaitov
|
3
|
+
#
|
4
|
+
# This file is part of EDango.
|
5
|
+
#
|
6
|
+
# EDango is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# EDango is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with EDango. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module EDango
|
20
|
+
|
21
|
+
class Core < SERVICES[:web, :raw]
|
22
|
+
set :run, true
|
23
|
+
set :lock, true
|
24
|
+
|
25
|
+
set :app_file, DIRS[:site]
|
26
|
+
set :root, DIRS[:site]
|
27
|
+
|
28
|
+
set :public, DIRS[:public]
|
29
|
+
set :views, DIRS[:views]
|
30
|
+
|
31
|
+
set :raise_errors, proc { test? }
|
32
|
+
set :dump_errors, proc { test? }
|
33
|
+
|
34
|
+
enable :sessions
|
35
|
+
enable :static
|
36
|
+
enable :clean_trace
|
37
|
+
|
38
|
+
disable :show_exceptions
|
39
|
+
disable :methodoverride
|
40
|
+
|
41
|
+
configure do
|
42
|
+
set :options, SERVICES[:environment].options
|
43
|
+
|
44
|
+
set :environment, (ENV['RACK_ENV'] || options[:environment]).intern()
|
45
|
+
|
46
|
+
set :sites, options[:sites]
|
47
|
+
set :server, options[:servers]
|
48
|
+
set :host, options[:host]
|
49
|
+
set :port, options[:port]
|
50
|
+
|
51
|
+
set :logging, options[:server_logging]
|
52
|
+
|
53
|
+
Rack::Mime::MIME_TYPES['.torrent'] = 'application/x-bittorrent'
|
54
|
+
|
55
|
+
options[:parameters].each do |param, value|
|
56
|
+
self.class.set(param, value)
|
57
|
+
end
|
58
|
+
|
59
|
+
set :errors, {}
|
60
|
+
end
|
61
|
+
|
62
|
+
helpers do
|
63
|
+
def error(key, value = nil)
|
64
|
+
value ? options.errors[key] = value : options.errors[key]
|
65
|
+
end
|
66
|
+
alias err error
|
67
|
+
|
68
|
+
def error?(key)
|
69
|
+
options.errors[key] ? true : false
|
70
|
+
end
|
71
|
+
alias err? error?
|
72
|
+
|
73
|
+
def clear_errors
|
74
|
+
options.errors.clear()
|
75
|
+
end
|
76
|
+
|
77
|
+
def current_jlib
|
78
|
+
options.environment == :production ? 'jquery.min.js' : 'jquery.js'
|
79
|
+
end
|
80
|
+
|
81
|
+
def url_input_class
|
82
|
+
error?(:in_url) ? 'err-text' : 'normal-text'
|
83
|
+
end
|
84
|
+
|
85
|
+
def passkey_input_class
|
86
|
+
error?(:in_passkey) ? 'err-text' : 'normal-text'
|
87
|
+
end
|
88
|
+
|
89
|
+
def emphasize(text, part = ':')
|
90
|
+
text.gsub(part, "<em>#{part}</em>")
|
91
|
+
end
|
92
|
+
|
93
|
+
def sanitize(file_name)
|
94
|
+
file_name.gsub(%r{\\|/|\.\.}, '') rescue ''
|
95
|
+
end
|
96
|
+
|
97
|
+
def link(ticket_path)
|
98
|
+
"tickets/#{file(ticket_path)}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def file(ticket_path)
|
102
|
+
File.basename(File.expand_path(ticket_path))
|
103
|
+
end
|
104
|
+
|
105
|
+
def process_root
|
106
|
+
@url = request.cookies['url']
|
107
|
+
@passkey = request.cookies['passkey']
|
108
|
+
|
109
|
+
haml(:index)
|
110
|
+
ensure
|
111
|
+
clear_errors()
|
112
|
+
end
|
113
|
+
|
114
|
+
def extract_tickets(url, passkey)
|
115
|
+
unless url.nil_or_empty? or
|
116
|
+
passkey.nil_or_empty?
|
117
|
+
|
118
|
+
sites = options.sites.select do |item|
|
119
|
+
url =~ Regexp.new(item.first) rescue false
|
120
|
+
end
|
121
|
+
|
122
|
+
logic = EDango::SERVICES[:logic]
|
123
|
+
result = logic.process(url, passkey, sites)
|
124
|
+
|
125
|
+
unless logic.errors.empty?
|
126
|
+
error :in_process, logic.errors
|
127
|
+
end
|
128
|
+
|
129
|
+
result
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
get '/' do
|
135
|
+
process_root()
|
136
|
+
end
|
137
|
+
post '/' do
|
138
|
+
process_root()
|
139
|
+
end
|
140
|
+
|
141
|
+
post '/process' do
|
142
|
+
url, passkey = params[:url], params[:passkey]
|
143
|
+
|
144
|
+
response.set_cookie('passkey', passkey)
|
145
|
+
|
146
|
+
error :in_url, t(:empty_url) if url.nil_or_empty?
|
147
|
+
error :in_passkey, t(:empty_passkey) if passkey.nil_or_empty?
|
148
|
+
|
149
|
+
@tickets = extract_tickets(url, passkey)
|
150
|
+
|
151
|
+
unless options.errors.empty?
|
152
|
+
response.set_cookie('url', url)
|
153
|
+
|
154
|
+
redirect('/')
|
155
|
+
else
|
156
|
+
response.delete_cookie('url')
|
157
|
+
|
158
|
+
haml(:result)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
get '/tickets/:ticket' do
|
163
|
+
file = File.join(EDango::DIRS[:tickets], sanitize(params[:ticket]))
|
164
|
+
|
165
|
+
if File.directory?(file) or not File.exists?(file)
|
166
|
+
error :in_process, [[t(:specified_file), t(:file_not_found)]]
|
167
|
+
end
|
168
|
+
|
169
|
+
unless options.errors.empty?
|
170
|
+
redirect('/')
|
171
|
+
else
|
172
|
+
send_file(file)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
not_found do
|
177
|
+
redirect('/')
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|