bilibili_sunday 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 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: []