bilibili_sunday 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'aria2-ruby', github: 'isundaylee/aria2-ruby'
4
+
5
+ # Specify your gem's dependencies in bilibili_sunday.gemspec
6
+ gemspec
7
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jiahao Li
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # BilibiliSunday
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'bilibili_sunday'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install bilibili_sunday
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bilibili_sunday/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bilibili_sunday"
8
+ spec.version = BilibiliSunday::VERSION
9
+ spec.authors = ["Jiahao Li"]
10
+ spec.email = ["isundaylee.reg@gmail.com"]
11
+ spec.description = %q{A Bilibili downloader! }
12
+ spec.summary = %q{A Bilibili downloader! }
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "aria2-ruby"
25
+ spec.add_dependency "nokogiri"
26
+ spec.add_dependency "xml-simple"
27
+ spec.add_dependency "webrick"
28
+ end
data/bin/bsdownload ADDED
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+ #!/usr/bin/env ruby
3
+
4
+ require 'bilibili_sunday/client'
5
+
6
+ url = ARGV[0]
7
+ host = ARGV[1]
8
+ client = BilibiliSunday::Client.new(host)
9
+
10
+ client.request_cache(client.cid_for_video_url(url))
data/bin/bsdv ADDED
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+ #!/usr/bin/env ruby
3
+
4
+ require 'bilibili_sunday/client'
5
+
6
+ url = ARGV[0]
7
+ host = ARGV[1]
8
+ client = BilibiliSunday::Client.new(host)
9
+
10
+ cid = client.cid_for_video_url(url)
11
+ title = client.title_for_video_url(url)
12
+ videos = client.all_videos
13
+
14
+ client.request_cache(cid) unless videos.include?(cid)
15
+
16
+ def print_bar(progress)
17
+ width = @width - 20
18
+ length = (width * progress).to_i
19
+
20
+ print ' '
21
+ print '#' * length
22
+ print ' ' * (width - length)
23
+ print ' '
24
+ print "%3.6f\%" % (100 * progress)
25
+ puts
26
+ end
27
+
28
+ def print_status(status)
29
+
30
+ puts " #{status['cid']}: #{status['status']} - #{status['path']}"
31
+
32
+ status['downloads'].each do |download|
33
+ print_bar(download['status']['progress'].to_f)
34
+ end
35
+
36
+ end
37
+
38
+ while true
39
+
40
+ @width = `tput cols`.to_i
41
+
42
+ divider = '-' * @width
43
+ status = client.query_status(cid)
44
+
45
+ system('clear')
46
+
47
+ puts divider
48
+
49
+ puts title
50
+
51
+ puts divider
52
+
53
+ print_status(status)
54
+
55
+ puts divider
56
+
57
+ puts "Update Time: #{Time.now}"
58
+
59
+ puts divider
60
+
61
+ sleep 1
62
+
63
+ end
data/bin/bsmonitor ADDED
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ #!/usr/bin/env ruby
3
+
4
+ require 'bilibili_sunday/client'
5
+
6
+ def print_bar(progress)
7
+ width = @width - 20
8
+ length = (width * progress).to_i
9
+
10
+ print ' '
11
+ print '#' * length
12
+ print ' ' * (width - length)
13
+ print ' '
14
+ print "%3.6f\%" % (100 * progress)
15
+ puts
16
+ end
17
+
18
+ def print_status(status)
19
+
20
+ puts " #{status['cid']}: #{status['status']} - #{status['path']}"
21
+
22
+ status['downloads'].each do |download|
23
+ print_bar(download['status']['progress'].to_f)
24
+ end
25
+
26
+ end
27
+
28
+ host = ARGV[0]
29
+ client = BilibiliSunday::Client.new(host)
30
+
31
+ while true
32
+
33
+ @width = `tput cols`.to_i
34
+
35
+ divider = '-' * @width
36
+
37
+ videos_list = client.all_videos.map { |x| x.to_i }
38
+
39
+ statuses = []
40
+
41
+ videos_list.each do |cid|
42
+ statuses << client.query_status(cid)
43
+ end
44
+
45
+ system('clear')
46
+
47
+ puts divider
48
+
49
+ statuses.each do |status|
50
+ print_status(status)
51
+ puts divider
52
+ end
53
+
54
+ puts "Update Time: #{Time.now}"
55
+
56
+ puts divider
57
+
58
+ sleep 1
59
+
60
+ end
data/bin/bsserver ADDED
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ #!/usr/bin/env ruby
3
+
4
+ require 'bilibili_sunday/server'
5
+
6
+ server = BilibiliSunday::Server.new
7
+ server.start
@@ -0,0 +1,42 @@
1
+ module BilibiliSunday
2
+
3
+ class Cacher
4
+
5
+ require 'fileutils'
6
+ require 'open-uri'
7
+ require 'digest/md5'
8
+
9
+ def initialize(dir)
10
+ @dir = dir
11
+
12
+ FileUtils.mkdir_p(@dir)
13
+ end
14
+
15
+ def read_url(url)
16
+ cached?(url) ?
17
+ cached_content(url) :
18
+ write_cache_for_url(url, open(url).read)
19
+ end
20
+
21
+ private
22
+
23
+ def cached?(url)
24
+ File.exists?(cache_path_for_url(url))
25
+ end
26
+
27
+ def cached_content(url)
28
+ File.open(cache_path_for_url(url)) { |f| f.read }
29
+ end
30
+
31
+ def write_cache_for_url(url, content)
32
+ File.open(cache_path_for_url(url), 'w') { |f| f.write(content) }
33
+ content
34
+ end
35
+
36
+ def cache_path_for_url(url)
37
+ File.join(@dir, Digest::MD5.hexdigest(url))
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,81 @@
1
+ require 'bilibili_sunday'
2
+
3
+ module BilibiliSunday
4
+
5
+ require 'base64'
6
+ require 'json'
7
+
8
+ class Client
9
+
10
+ DEFAULT_HOST = '127.0.0.1'
11
+ DEFAULT_PORT = 10753
12
+
13
+ def initialize(host = nil, port = nil, working_dir = nil)
14
+ @host = host || DEFAULT_HOST
15
+ @port = port || DEFAULT_PORT
16
+ end
17
+
18
+ def cid_for_video_url(url)
19
+ rpc_call('cid_for_video_url', [url])
20
+ end
21
+
22
+ def title_for_video_url(url)
23
+ rpc_call('title_for_video_url', [url])
24
+ end
25
+
26
+ def request_cache(cid)
27
+ rpc_call('request_cache', [cid])
28
+ end
29
+
30
+ def all_videos
31
+ rpc_call('all_videos', [])
32
+ end
33
+
34
+ def active_videos
35
+ rpc_call('active_videos', [])
36
+ end
37
+
38
+ def query_status(cid)
39
+ rpc_call('query_status', [cid])
40
+ end
41
+
42
+ private
43
+
44
+ def get(url, params = {})
45
+ uri = URI.parse(url)
46
+
47
+ uri.query = URI.encode_www_form(params)
48
+
49
+ http = Net::HTTP.new(uri.host, uri.port)
50
+ request = Net::HTTP::Get.new(uri.request_uri)
51
+
52
+ response = http.request(request)
53
+
54
+ {
55
+ 'code' => response.code.to_i,
56
+ 'body' => response.body
57
+ }
58
+ end
59
+
60
+ def rpc_path
61
+ "http://#{@host}:#{@port}/jsonrpc"
62
+ end
63
+
64
+ def rpc_call(method, params)
65
+ method = "bilibili_sunday.#{method}"
66
+ id = 'bilibili_sunday_client'
67
+ params_encoded = Base64.encode64(JSON.generate(params))
68
+
69
+ response = get("#{rpc_path}", {'method' => method, 'id' => id, 'params' => params_encoded})
70
+ answer = JSON.parse(response['body'])
71
+
72
+ if response['code'] == 200
73
+ answer['result']
74
+ else
75
+ raise "BilibiliSunday Server error #{answer['error']['code'].to_i}: #{answer['error']['message']}"
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,312 @@
1
+ require 'bilibili_sunday/cacher'
2
+
3
+ module BilibiliSunday
4
+
5
+ class Downloader
6
+
7
+ require 'fileutils'
8
+ require 'yaml'
9
+ require 'digest/md5'
10
+ require 'aria2'
11
+ require 'nokogiri'
12
+ require 'xmlsimple'
13
+ require 'uri'
14
+ require 'open-uri'
15
+ require 'logger'
16
+
17
+ def initialize(work_path = nil, downloader = nil, logger = nil)
18
+ @work_path = File.expand_path(work_path || '~/.bilibili_sunday')
19
+ @downloader = downloader || Aria2::Downloader.new
20
+ @logger = logger || Logger.new($stdout)
21
+ @cacher = BilibiliSunday::Cacher.new(cacher_store_path)
22
+
23
+ FileUtils.mkdir_p(@work_path)
24
+ end
25
+
26
+ def routine_work
27
+ @logger.info 'Carrying out routine work. '
28
+
29
+ videos = all_videos
30
+
31
+ videos.each do |cid|
32
+ update_status(cid)
33
+ concat(cid) if (cache_completed?(cid) && (!concat_started?(cid)))
34
+ end
35
+ end
36
+
37
+ def query_status(cid)
38
+ status = :unknown
39
+ status = :caching if cache_in_progress?(cid)
40
+ status = :concatenating if concat_in_progress?(cid)
41
+ status = :complete if concat_completed?(cid)
42
+
43
+ {
44
+ cid: cid,
45
+ status: status,
46
+ downloads: load_yaml(status_yaml_path(cid)) || [],
47
+ path: concat_completed?(cid) ? concat_output_file_path(cid) : nil
48
+ }
49
+ end
50
+
51
+ def request_cache(cid)
52
+ cache(cid)
53
+ end
54
+
55
+ def all_videos
56
+ Dir.glob(File.join(video_store_path, '*')).select {|f| File.directory? f}.map { |f| File.basename(f).to_i }
57
+ end
58
+
59
+ def cid_for_video_url(url)
60
+ doc = Nokogiri::HTML(gzip_inflate(@cacher.read_url(url)))
61
+
62
+ doc.css('.scontent').each do |i|
63
+ res = /cid=([0-9]*)/.match(i.to_s)
64
+
65
+ if res && res[1]
66
+ return res[1].to_i
67
+ else
68
+ raise "Not a valid Bilibili video page URL. "
69
+ end
70
+ end
71
+
72
+ raise "Not a valid Bilibili video page URL. "
73
+ end
74
+
75
+ def title_for_video_url(url)
76
+ doc = Nokogiri::HTML(gzip_inflate(@cacher.read_url(url)))
77
+
78
+ doc.css('meta').each do |i|
79
+ return i['content'] if i['name'] == 'title'
80
+ end
81
+
82
+ raise "Not a valid Bilibili video page URL. "
83
+ end
84
+
85
+ def active_videos
86
+ all_videos.select { |i| !concat_completed?(i)}
87
+ end
88
+
89
+ private
90
+
91
+ def gzip_inflate(string)
92
+ # TODO Ugly workaround...
93
+ begin
94
+ Zlib::GzipReader.new(StringIO.new(string)).read
95
+ rescue
96
+ string
97
+ end
98
+ end
99
+
100
+ def update_status(cid)
101
+ # If download has not started yet, skip updating status.
102
+ return unless cache_started?(cid)
103
+
104
+ # If download already completed, skip updating status.
105
+ return if cache_completed?(cid)
106
+
107
+ downloads = load_yaml(downloads_yaml_path(cid))
108
+ old_status = load_yaml(status_yaml_path(cid))
109
+
110
+ status = []
111
+ incomplete = false
112
+
113
+ downloads.each_with_index do |download, order|
114
+ # If already completed, stop updating status.
115
+ if old_status
116
+ last_status = old_status[order][:status]
117
+ if last_status['status'] == 'complete'
118
+ download[:status] = last_status
119
+ status << download
120
+ next
121
+ end
122
+ end
123
+
124
+ download[:status] = @downloader.query_status(download[:download_id])
125
+ incomplete = true unless download[:status]['status'] == 'complete'
126
+ status << download
127
+ end
128
+
129
+ write_yaml(status_yaml_path(cid), status)
130
+ mark_cache_complete(cid) unless incomplete
131
+ end
132
+
133
+ def load_yaml(path)
134
+ File.exists?(path) ?
135
+ YAML.load(File.open(path) { |f| f.read }) :
136
+ nil
137
+ end
138
+
139
+ def write_yaml(path, obj)
140
+ FileUtils.mkdir_p(File.dirname(path))
141
+ File.open(path, 'w') { |f| f.write(YAML.dump(obj))}
142
+ end
143
+
144
+ def yaml_exists?(rel_path)
145
+ File.exists?(rel_path)
146
+ end
147
+
148
+ def fetch_filelist(cid)
149
+ url = "http://interface.bilibili.tv/v_cdn_play?cid=#{cid}"
150
+ xml = XmlSimple::xml_in(@cacher.read_url(url))
151
+
152
+ filelist = [''] * xml['durl'].length
153
+
154
+ xml['durl'].each do |file|
155
+ order = file['order'][0].to_i
156
+ url = file['url'][0]
157
+ filelist[order - 1] = url
158
+ end
159
+
160
+ filelist
161
+ end
162
+
163
+ def mark_cache_complete(cid)
164
+ write_yaml(downloaded_yaml_path(cid), true)
165
+ end
166
+
167
+ def mark_concat_complete(cid)
168
+ write_yaml(concatenated_yaml_path(cid), true)
169
+ end
170
+
171
+ def video_store_path
172
+ File.join(@work_path, "store")
173
+ end
174
+
175
+ def video_path(cid)
176
+ File.join(video_store_path, "#{cid}")
177
+ end
178
+
179
+ def cache_started?(cid)
180
+ yaml_exists?(downloads_yaml_path(cid))
181
+ end
182
+
183
+ def cache_completed?(cid)
184
+ yaml_exists?(downloaded_yaml_path(cid))
185
+ end
186
+
187
+ def cache_in_progress?(cid)
188
+ cache_started?(cid) && (!cache_completed?(cid))
189
+ end
190
+
191
+ def concat_started?(cid)
192
+ yaml_exists?(ffmpeg_concat_input_path(cid))
193
+ end
194
+
195
+ def concat_completed?(cid)
196
+ yaml_exists?(concatenated_yaml_path(cid))
197
+ end
198
+
199
+ def concat_in_progress?(cid)
200
+ concat_started?(cid) && (!concat_completed?(cid))
201
+ end
202
+
203
+ def downloads_yaml_path(cid)
204
+ File.join(video_path(cid), 'downloads.yml')
205
+ end
206
+
207
+ def downloaded_yaml_path(cid)
208
+ File.join(video_path(cid), 'downloaded.yml')
209
+ end
210
+
211
+ def concatenated_yaml_path(cid)
212
+ File.join(video_path(cid), 'concatenated.yaml')
213
+ end
214
+
215
+ def cacher_store_path
216
+ File.join(@work_path, 'cache')
217
+ end
218
+
219
+ def video_ext(cid)
220
+ # TODO better way of identifying file types
221
+ downloads = load_yaml(downloads_yaml_path(cid))
222
+ ext = File.extname(downloads[0][:path])
223
+ ext && !ext.empty? ?
224
+ ext :
225
+ '.flv'
226
+ end
227
+
228
+ def fix_extname(extname)
229
+ return '.flv' if extname == '.hlv'
230
+ extname
231
+ end
232
+
233
+ def concat_output_file_path(cid)
234
+ File.join(video_path(cid), "entirety#{video_ext(cid)}")
235
+ end
236
+
237
+ def status_yaml_path(cid)
238
+ File.join(video_path(cid), 'status.yaml')
239
+ end
240
+
241
+ def ffmpeg_concat_input_path(cid)
242
+ File.join(video_path(cid), 'concat_list')
243
+ end
244
+
245
+ def cache(cid)
246
+ return false if cache_started?(cid)
247
+
248
+ FileUtils.mkdir_p(video_path(cid))
249
+
250
+ filelist = fetch_filelist(cid)
251
+ downloads = []
252
+
253
+ filelist.each_with_index do |url, order|
254
+ to_name = "#{order}#{fix_extname(File.extname(URI.parse(url).path))}"
255
+ to_path = File.join(video_path(cid), to_name)
256
+
257
+ downloads << {
258
+ order: order,
259
+ url: url,
260
+ download_id: @downloader.download(url, to_path),
261
+ path: to_path
262
+ }
263
+ end
264
+
265
+ write_yaml(downloads_yaml_path(cid), downloads)
266
+
267
+ true
268
+ end
269
+
270
+ def write_ffmpeg_concat_input_file(cid)
271
+ downloads = load_yaml(downloads_yaml_path(cid))
272
+
273
+ File.open(ffmpeg_concat_input_path(cid), 'w') do |f|
274
+ downloads.sort_by! { |f| f[:order] }
275
+
276
+ downloads.each do |v|
277
+ f.puts "file '#{v[:path]}'"
278
+ end
279
+ end
280
+ end
281
+
282
+ def remove_ffmpeg_concat_input_file(cid)
283
+ FileUtils.rm(ffmpeg_concat_input_path(cid))
284
+ end
285
+
286
+ def concat(cid)
287
+ return false if concat_started?(cid)
288
+
289
+ unless cache_completed?(cid)
290
+ raise "Cannot concat clips. Downloads not completed. "
291
+ end
292
+
293
+ write_ffmpeg_concat_input_file(cid)
294
+
295
+ Thread.start(cid) do |cid|
296
+ ffmpeg = "ffmpeg"
297
+ command = "\"#{ffmpeg}\" -f concat -i \"#{ffmpeg_concat_input_path(cid)}\" -c copy \"#{concat_output_file_path(cid)}\""
298
+
299
+ system(command)
300
+
301
+ if $? == 0
302
+ mark_concat_complete(cid)
303
+ else
304
+ remove_ffmpeg_concat_input_file(cid)
305
+ end
306
+ end
307
+
308
+ end
309
+
310
+ end
311
+
312
+ end
@@ -0,0 +1,145 @@
1
+ require 'bilibili_sunday/downloader'
2
+ require 'webrick'
3
+
4
+ module BilibiliSunday
5
+
6
+ require 'base64'
7
+ require 'json'
8
+
9
+ class RequestHandler
10
+
11
+ def initialize(downloader)
12
+ @downloader = downloader
13
+ end
14
+
15
+ def handle_request(method, params)
16
+ begin
17
+ result = /^bilibili_sunday.(.*?)$/.match(method)
18
+
19
+ return handle_error(1, 'No matching method. ') unless result
20
+
21
+ method = result[1]
22
+
23
+ if method == 'cid_for_video_url'
24
+ handle_cid_for_video_url(params[0])
25
+ elsif method == 'title_for_video_url'
26
+ handle_title_for_video_url(params[0])
27
+ elsif method == 'request_cache'
28
+ handle_request_cache(params[0].to_i)
29
+ elsif method == 'query_status'
30
+ handle_query_status(params[0].to_i)
31
+ elsif method == 'all_videos'
32
+ handle_all_videos
33
+ elsif method == 'active_videos'
34
+ handle_active_videos
35
+ else
36
+ handle_error(1, 'No matching method. ')
37
+ end
38
+ rescue
39
+ return handle_error(2, 'Internal server error. ')
40
+ end
41
+ end
42
+
43
+ def handle_cid_for_video_url(url)
44
+ return 200, {result: @downloader.cid_for_video_url(url)}
45
+ end
46
+
47
+ def handle_title_for_video_url(url)
48
+ return 200, {result: @downloader.title_for_video_url(url)}
49
+ end
50
+
51
+ def handle_request_cache(cid)
52
+ return 200, {result: @downloader.request_cache(cid)}
53
+ end
54
+
55
+ def handle_query_status(cid)
56
+ return 200, {result: @downloader.query_status(cid)}
57
+ end
58
+
59
+ def handle_all_videos
60
+ return 200, {result: @downloader.all_videos}
61
+ end
62
+
63
+ def handle_active_videos
64
+ return 200, {result: @downloader.active_videos}
65
+ end
66
+
67
+ def handle_error(error_code, error_message)
68
+ return 500, {error: {code: error_code, message: error_message}}
69
+ end
70
+
71
+ end
72
+
73
+ class Servlet < WEBrick::HTTPServlet::AbstractServlet
74
+
75
+ def initialize(server, downloader)
76
+ super(server)
77
+ @handler = RequestHandler.new(downloader)
78
+ end
79
+
80
+ def do_GET(request, response)
81
+ id = request.query["id"]
82
+ method = request.query["method"]
83
+ params = JSON.parse(Base64.decode64(request.query["params"]))
84
+
85
+ code, result = @handler.handle_request(method, params)
86
+ result[:id] = id
87
+ result[:jsonrpc] = '2.0'
88
+
89
+ response.status = code
90
+ response['Content-Type'] = 'application/json'
91
+ response['Access-Control-Allow-Origin'] = '*'
92
+ response.body = result.to_json
93
+ end
94
+
95
+ end
96
+
97
+ class Server
98
+
99
+ require 'json'
100
+
101
+ DEFAULT_PORT = 10753
102
+
103
+ def initialize(port = DEFAULT_PORT, working_dir = nil)
104
+ @port = port
105
+ @downloader = Downloader.new(working_dir || File.expand_path("~/.bilibili_sunday"))
106
+ end
107
+
108
+ def start
109
+ @running = true
110
+
111
+ @downloader_thread = Thread.new do
112
+ while true
113
+ @downloader.routine_work
114
+ sleep 1
115
+ end
116
+ end
117
+
118
+ @rpc_server_thread = Thread.new do
119
+ begin
120
+ server = WEBrick::HTTPServer.new(:Port => @port)
121
+ server.mount "/jsonrpc", Servlet, @downloader
122
+ server.start
123
+ rescue
124
+ ensure
125
+ server.shutdown
126
+ end
127
+ end
128
+
129
+ while true
130
+ unless @running
131
+ @downloader_thread.terminate
132
+ @rpc_server_thread.terminate
133
+ break
134
+ end
135
+ sleep 1
136
+ end
137
+ end
138
+
139
+ def stop
140
+ @running = false
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,3 @@
1
+ module BilibiliSunday
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "bilibili_sunday/version"
2
+ require "bilibili_sunday/downloader"
3
+
4
+ module BilibiliSunday
5
+ # Your code goes here...
6
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bilibili_sunday
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jiahao Li
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: aria2-ruby
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: nokogiri
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: xml-simple
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: webrick
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: ! 'A Bilibili downloader! '
111
+ email:
112
+ - isundaylee.reg@gmail.com
113
+ executables:
114
+ - bsdownload
115
+ - bsdv
116
+ - bsmonitor
117
+ - bsserver
118
+ extensions: []
119
+ extra_rdoc_files: []
120
+ files:
121
+ - .gitignore
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - bilibili_sunday.gemspec
127
+ - bin/bsdownload
128
+ - bin/bsdv
129
+ - bin/bsmonitor
130
+ - bin/bsserver
131
+ - lib/bilibili_sunday.rb
132
+ - lib/bilibili_sunday/cacher.rb
133
+ - lib/bilibili_sunday/client.rb
134
+ - lib/bilibili_sunday/downloader.rb
135
+ - lib/bilibili_sunday/server.rb
136
+ - lib/bilibili_sunday/version.rb
137
+ homepage: ''
138
+ licenses:
139
+ - MIT
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ! '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 1.8.24
159
+ signing_key:
160
+ specification_version: 3
161
+ summary: A Bilibili downloader!
162
+ test_files: []