xunlei 0.0.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/.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
|