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.
Files changed (47) hide show
  1. data/Copying.txt +679 -0
  2. data/History.txt +6 -0
  3. data/Manifest.txt +46 -0
  4. data/PostInstall.txt +6 -0
  5. data/README.rdoc +117 -0
  6. data/Rakefile +21 -0
  7. data/bin/edango +34 -0
  8. data/lib/edango.rb +42 -0
  9. data/lib/edango/context.rb +23 -0
  10. data/lib/edango/context/directories.rb +67 -0
  11. data/lib/edango/context/files.rb +37 -0
  12. data/lib/edango/context/language.rb +101 -0
  13. data/lib/edango/context/parameters.rb +44 -0
  14. data/lib/edango/context/services.rb +147 -0
  15. data/lib/edango/di/container.rb +160 -0
  16. data/lib/edango/di/helpers.rb +41 -0
  17. data/lib/edango/di/proxy.rb +54 -0
  18. data/lib/edango/di/service.rb +60 -0
  19. data/lib/edango/di/service_factory.rb +40 -0
  20. data/lib/edango/environment.rb +77 -0
  21. data/lib/edango/executor.rb +64 -0
  22. data/lib/edango/helpers/hash.rb +30 -0
  23. data/lib/edango/helpers/kernel.rb +41 -0
  24. data/lib/edango/helpers/object.rb +65 -0
  25. data/lib/edango/helpers/string.rb +29 -0
  26. data/lib/edango/helpers/symbol.rb +39 -0
  27. data/lib/edango/logic/ticket_extractor.rb +258 -0
  28. data/lib/edango/site/core.rb +182 -0
  29. data/lib/edango/site/public/favicon.ico +0 -0
  30. data/lib/edango/site/public/images/btn-back-help.png +0 -0
  31. data/lib/edango/site/public/images/bullet.png +0 -0
  32. data/lib/edango/site/public/images/ctrl-back.gif +0 -0
  33. data/lib/edango/site/public/images/frm-back-err.png +0 -0
  34. data/lib/edango/site/public/images/frm-back-help.png +0 -0
  35. data/lib/edango/site/public/images/frm-back.png +0 -0
  36. data/lib/edango/site/public/images/logo.png +0 -0
  37. data/lib/edango/site/public/scripts/jquery.js +4376 -0
  38. data/lib/edango/site/public/scripts/jquery.min.js +19 -0
  39. data/lib/edango/site/public/scripts/logic.js +6 -0
  40. data/lib/edango/site/public/styles/layout.css +270 -0
  41. data/lib/edango/site/views/errors.haml +12 -0
  42. data/lib/edango/site/views/help.haml +10 -0
  43. data/lib/edango/site/views/index.haml +27 -0
  44. data/lib/edango/site/views/layout.haml +15 -0
  45. data/lib/edango/site/views/result.haml +10 -0
  46. data/lib/edango/starter.rb +141 -0
  47. 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