xunlei 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Gemfile.ci +3 -0
- data/Guardfile +5 -0
- data/README.md +40 -0
- data/Rakefile +1 -0
- data/bin/xunlei +199 -0
- data/lib/xunlei.rb +3 -0
- data/lib/xunlei/engine.rb +132 -0
- data/lib/xunlei/version.rb +3 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/xunlei/engine_spec.rb +3 -0
- data/xunlei.gemspec +25 -0
- metadata +95 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.ci
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
xunlei gem
|
2
|
+
===========
|
3
|
+
|
4
|
+
lixian.vip.xunlei.com utility script for Mac OS X users
|
5
|
+
|
6
|
+
Summary:
|
7
|
+
-----------
|
8
|
+
|
9
|
+
This is a browser script for lixian.vip.xunlei.com.
|
10
|
+
It drives Google Chrome to do automation tasks for you, so please
|
11
|
+
make sure you have Google Chrome installed first.
|
12
|
+
|
13
|
+
WARNING:
|
14
|
+
it stores your USERNAME and PASSWORD for
|
15
|
+
lixian.vip.xunlei.com as PLAINTEXT at ~/.xunlei/credentials.yml
|
16
|
+
|
17
|
+
Install:
|
18
|
+
-----------
|
19
|
+
|
20
|
+
gem install xunlei
|
21
|
+
|
22
|
+
Usage:
|
23
|
+
-----------
|
24
|
+
|
25
|
+
Dump all tasks from web:
|
26
|
+
|
27
|
+
xunlei dump_tasks
|
28
|
+
|
29
|
+
Download files
|
30
|
+
|
31
|
+
xunlei download
|
32
|
+
|
33
|
+
Download files according to pattern in file names
|
34
|
+
|
35
|
+
xunlei download --only matrix
|
36
|
+
xunlei download --except bourne
|
37
|
+
|
38
|
+
Pass --help to see more tasks and options
|
39
|
+
|
40
|
+
xunlei --help
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/xunlei
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "xunlei"
|
4
|
+
require "yaml"
|
5
|
+
require "commander/import"
|
6
|
+
|
7
|
+
program :name, "Xunlei"
|
8
|
+
program :version, Xunlei::VERSION
|
9
|
+
program :description, "lixian.vip.xunlei.com utility script"
|
10
|
+
|
11
|
+
def filter_files(options = nil)
|
12
|
+
files = []
|
13
|
+
YAML.load_file(xunlei_tasks_path).each do |file|
|
14
|
+
if !options.only.nil?
|
15
|
+
files << file if file[:name] =~ /#{options.only}/i
|
16
|
+
elsif !options.except.nil?
|
17
|
+
files << file unless file[:name] =~ /#{options.except}/i
|
18
|
+
else
|
19
|
+
files << file
|
20
|
+
end
|
21
|
+
end
|
22
|
+
files
|
23
|
+
end
|
24
|
+
|
25
|
+
def do_dump_cookies(c)
|
26
|
+
c.option "--driver DRIVER", String, "use a different webdriver (e.g. firefox). default is chrome"
|
27
|
+
c.action do |args, options|
|
28
|
+
options.default :driver => "chrome"
|
29
|
+
|
30
|
+
check_for_config_files
|
31
|
+
check_for_chromedriver
|
32
|
+
credentials = YAML.load_file(xunlei_credential_file_path)
|
33
|
+
engine = Xunlei::Engine.new(credentials[:username], credentials[:password], options.driver.downcase.to_sym)
|
34
|
+
|
35
|
+
File.open(xunlei_cookies_path, "w") do |file|
|
36
|
+
engine.dump_cookies.each do |line|
|
37
|
+
file.write(line)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
yield(engine) if block_given?
|
42
|
+
|
43
|
+
engine.stop
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def xunlei_cookies_path
|
48
|
+
File.join(xunlei_folder_path, "cookies.txt")
|
49
|
+
end
|
50
|
+
|
51
|
+
def xunlei_tasks_path
|
52
|
+
File.join(xunlei_folder_path, "all_tasks.yml")
|
53
|
+
end
|
54
|
+
|
55
|
+
def xunlei_credential_file_path
|
56
|
+
File.join(xunlei_folder_path, "credentials.yml")
|
57
|
+
end
|
58
|
+
|
59
|
+
def xunlei_folder_name
|
60
|
+
"~/.xunlei"
|
61
|
+
end
|
62
|
+
|
63
|
+
def xunlei_folder_path
|
64
|
+
File.expand_path(xunlei_folder_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def xunlei_folder_exists?
|
68
|
+
Dir.exists?(xunlei_folder_path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def credential_file_exists?
|
72
|
+
File.exists?(xunlei_credential_file_path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_xunlei_folder
|
76
|
+
Dir.mkdir(xunlei_folder_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ask_for_credentials
|
80
|
+
puts "#{xunlei_credential_file_path} not exists. Now creating one."
|
81
|
+
puts "*** WARNING: your USERNAME and PASSWORD will be stored as PLAINTEXT at #{xunlei_credential_file_path} ***"
|
82
|
+
|
83
|
+
username = ask("Username: ")
|
84
|
+
password = ask("Password: ") { |q| q.echo = "*" }
|
85
|
+
File.open(xunlei_credential_file_path, "w") do |file|
|
86
|
+
file.write({ :username => username, :password => password }.to_yaml)
|
87
|
+
end
|
88
|
+
|
89
|
+
puts "#{xunlei_credential_file_path} successfully created."
|
90
|
+
end
|
91
|
+
|
92
|
+
def check_for_credentials
|
93
|
+
ask_for_credentials unless credential_file_exists?
|
94
|
+
end
|
95
|
+
|
96
|
+
def chromedriver_zip_name
|
97
|
+
"chromedriver_mac.zip"
|
98
|
+
end
|
99
|
+
|
100
|
+
def check_for_chromedriver
|
101
|
+
unless system("which chromedriver > /dev/null 2>&1")
|
102
|
+
puts "chromedriver not found in your PATH"
|
103
|
+
if agree("Would you like me to try download it for you? (yes or no)")
|
104
|
+
if system("wget 'http://chromium.googlecode.com/files/chromedriver_mac_16.0.902.0.zip' -O #{chromedriver_zip_name}")
|
105
|
+
if system("unzip #{chromedriver_zip_name}")
|
106
|
+
puts "moving chromedriver to /usr/local/bin ..."
|
107
|
+
system("mv -v chromedriver /usr/local/bin")
|
108
|
+
|
109
|
+
puts "deleting temporary files..."
|
110
|
+
system("rm -v #{chromedriver_zip_name}")
|
111
|
+
else
|
112
|
+
puts "`unzip` not found in your PATH. Try manually unzip #{chromedriver_zip_name} and move it to /usr/local/bin"
|
113
|
+
exit
|
114
|
+
end
|
115
|
+
end
|
116
|
+
else
|
117
|
+
puts "OK. You can download it manually here: http://code.google.com/p/chromium/downloads"
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def check_for_config_files
|
124
|
+
create_xunlei_folder unless xunlei_folder_exists?
|
125
|
+
check_for_credentials
|
126
|
+
end
|
127
|
+
|
128
|
+
command :dump_tasks do |c|
|
129
|
+
c.syntax= "dump_tasks"
|
130
|
+
c.description = "dump all files to #{xunlei_tasks_path}"
|
131
|
+
|
132
|
+
do_dump_cookies(c) do |engine|
|
133
|
+
tasks = engine.dump_tasks
|
134
|
+
|
135
|
+
File.open(xunlei_tasks_path, "w") do |file|
|
136
|
+
file.write(tasks.to_yaml)
|
137
|
+
end
|
138
|
+
|
139
|
+
puts "Successfully dumped following tasks:"
|
140
|
+
puts
|
141
|
+
tasks.each do |task|
|
142
|
+
puts task[:name]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
command :dump_cookies do |c|
|
148
|
+
c.syntax = "dump_cookies"
|
149
|
+
c.description = "dump cookies to #{xunlei_cookies_path}"
|
150
|
+
|
151
|
+
do_dump_cookies(c)
|
152
|
+
end
|
153
|
+
|
154
|
+
command :download do |c|
|
155
|
+
c.syntax = "download"
|
156
|
+
c.description = "download all files in #{xunlei_tasks_path}"
|
157
|
+
c.option "--only PATTERN", String, "only download files which names include PATTERN"
|
158
|
+
c.option "--except PATTERN", String, "do not download files which names include PATTERN"
|
159
|
+
|
160
|
+
c.action do |args, options|
|
161
|
+
options.default :only => nil, :except => nil
|
162
|
+
|
163
|
+
files = filter_files(options)
|
164
|
+
|
165
|
+
if files.empty?
|
166
|
+
puts "Nothing to do."
|
167
|
+
else
|
168
|
+
puts "\nAbout to download following files:"
|
169
|
+
puts
|
170
|
+
filter_files(options).each do |file|
|
171
|
+
puts file[:name]
|
172
|
+
end
|
173
|
+
|
174
|
+
if agree("\nConfirm? (yes or no)")
|
175
|
+
filter_files(options).each do |file|
|
176
|
+
cmd = "wget --load-cookies=#{xunlei_cookies_path} '#{file[:url]}' -c -O '#{file[:name]}'"
|
177
|
+
break unless system(cmd)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
command :show do |c|
|
185
|
+
c.syntax = "show"
|
186
|
+
c.description = "show files in #{xunlei_tasks_path}"
|
187
|
+
|
188
|
+
c.action do |args, options|
|
189
|
+
options.default :only => nil, :except => nil
|
190
|
+
puts "You have following files in your #{xunlei_tasks_path}:"
|
191
|
+
puts
|
192
|
+
filter_files(options).each do |file|
|
193
|
+
puts file[:name]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
alias_command :down, :download
|
199
|
+
alias_command :dump, :dump_tasks
|
data/lib/xunlei.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require "watir-webdriver"
|
2
|
+
|
3
|
+
module Xunlei
|
4
|
+
class Engine
|
5
|
+
def initialize(username, password, driver = :chrome)
|
6
|
+
@browser = Watir::Browser.new driver
|
7
|
+
@browser.goto "http://lixian.vip.xunlei.com"
|
8
|
+
|
9
|
+
@browser.text_field(:id => "u").when_present.set(username)
|
10
|
+
@browser.text_field(:id => "p_show").when_present.set(password)
|
11
|
+
@browser.button(:id => "button_submit4reg").when_present.click
|
12
|
+
end
|
13
|
+
|
14
|
+
def dump_cookies
|
15
|
+
# wait until cookies are ready
|
16
|
+
get_task_list
|
17
|
+
|
18
|
+
cookies = []
|
19
|
+
@browser.driver.manage.all_cookies.each do |cookie|
|
20
|
+
domain = cookie[:domain]
|
21
|
+
path = cookie[:path]
|
22
|
+
expires = cookie[:expires] ? cookie[:expires].strftime("%s") : "0"
|
23
|
+
name = cookie[:name]
|
24
|
+
value = cookie[:value]
|
25
|
+
cookies << "#{domain}\tTRUE\t#{path}\tFALSE\t#{expires}\t#{name}\t#{value}\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
cookies
|
29
|
+
end
|
30
|
+
|
31
|
+
def dump_tasks
|
32
|
+
all_files = []
|
33
|
+
|
34
|
+
begin
|
35
|
+
all_files += process_current_page
|
36
|
+
end while next_page
|
37
|
+
|
38
|
+
all_files
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop
|
42
|
+
@browser.close
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def wait_until_all_loaded
|
48
|
+
get_task_list
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_task_list
|
52
|
+
task_list = @browser.div(:id => "rowbox_list")
|
53
|
+
task_list.wait_until_present
|
54
|
+
task_list
|
55
|
+
end
|
56
|
+
|
57
|
+
def next_page
|
58
|
+
next_li = @browser.li(:class => "next")
|
59
|
+
if next_li.present?
|
60
|
+
next_li.as.first.click
|
61
|
+
true
|
62
|
+
else
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def process_current_page
|
68
|
+
task_list = get_task_list
|
69
|
+
|
70
|
+
all_files = []
|
71
|
+
|
72
|
+
task_list.divs(:class => "rw_list").each do |task_div|
|
73
|
+
all_files += process_task(task_div)
|
74
|
+
end
|
75
|
+
|
76
|
+
all_files
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_task(task_div)
|
80
|
+
task_files = []
|
81
|
+
|
82
|
+
task_div.wait_until_present
|
83
|
+
|
84
|
+
if task_is_ready?(task_div)
|
85
|
+
task_div.click
|
86
|
+
task_div.a(:class => "rwbtn ic_down").wait_until_present
|
87
|
+
|
88
|
+
if task_div.a(:class => "rwbtn ic_open").present?
|
89
|
+
task_files += process_bt_task(task_div)
|
90
|
+
else
|
91
|
+
task_files << process_normal_task(task_div)
|
92
|
+
end
|
93
|
+
else
|
94
|
+
# still downloading
|
95
|
+
end
|
96
|
+
|
97
|
+
task_files
|
98
|
+
end
|
99
|
+
|
100
|
+
def task_is_ready?(task_div)
|
101
|
+
task_div.em(:class => "loadnum").text == "100%"
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_normal_task(task_div)
|
105
|
+
normal_task_a = task_div.span(:class => "namelink").as.first
|
106
|
+
normal_task_input = task_div.input(:id => "dl_url" + task_div.id.gsub(/\D+/, ""))
|
107
|
+
{ :name => normal_task_a.text, :url => normal_task_input.value }
|
108
|
+
end
|
109
|
+
|
110
|
+
def process_bt_task(task_div)
|
111
|
+
task_files = []
|
112
|
+
task_div.a(:class => "rwbtn ic_open").when_present.click
|
113
|
+
|
114
|
+
folder_list = @browser.div(:id => "rwbox_bt_list")
|
115
|
+
folder_list.wait_until_present
|
116
|
+
|
117
|
+
folder_list.as(:name => "bturls").each do |a|
|
118
|
+
task_files << { :name => a.text, :url => a.href }
|
119
|
+
end
|
120
|
+
|
121
|
+
go_back_from_bt_task
|
122
|
+
|
123
|
+
task_files
|
124
|
+
end
|
125
|
+
|
126
|
+
def go_back_from_bt_task
|
127
|
+
back_div = @browser.div(:id => "view_bt_list_nav")
|
128
|
+
back_div.wait_until_present
|
129
|
+
back_div.lis(:class => "main_link main_linksub").first.a(:class => "btn_m").click
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/xunlei.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "xunlei/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "xunlei"
|
7
|
+
s.version = Xunlei::VERSION
|
8
|
+
s.authors = ["Forrest Ye"]
|
9
|
+
s.email = ["afu@forresty.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{A browser script to access lixian.vip.xunlei.com tasks automatically}
|
12
|
+
s.description = %q{A browser script to access lixian.vip.xunlei.com tasks automatically}
|
13
|
+
|
14
|
+
s.rubyforge_project = "xunlei"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rake"
|
22
|
+
|
23
|
+
s.add_runtime_dependency "watir-webdriver"
|
24
|
+
s.add_runtime_dependency "commander"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xunlei
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Forrest Ye
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-16 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &70288983816380 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70288983816380
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: watir-webdriver
|
27
|
+
requirement: &70288983815740 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70288983815740
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: commander
|
38
|
+
requirement: &70288983815280 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70288983815280
|
47
|
+
description: A browser script to access lixian.vip.xunlei.com tasks automatically
|
48
|
+
email:
|
49
|
+
- afu@forresty.com
|
50
|
+
executables:
|
51
|
+
- xunlei
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- .travis.yml
|
57
|
+
- Gemfile
|
58
|
+
- Gemfile.ci
|
59
|
+
- Guardfile
|
60
|
+
- README.md
|
61
|
+
- Rakefile
|
62
|
+
- bin/xunlei
|
63
|
+
- lib/xunlei.rb
|
64
|
+
- lib/xunlei/engine.rb
|
65
|
+
- lib/xunlei/version.rb
|
66
|
+
- spec/spec_helper.rb
|
67
|
+
- spec/xunlei/engine_spec.rb
|
68
|
+
- xunlei.gemspec
|
69
|
+
homepage: ''
|
70
|
+
licenses: []
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project: xunlei
|
89
|
+
rubygems_version: 1.8.10
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: A browser script to access lixian.vip.xunlei.com tasks automatically
|
93
|
+
test_files:
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
- spec/xunlei/engine_spec.rb
|