lknovel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
@@ -0,0 +1 @@
1
+ 0.0.1: Initial release.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lknovel.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Zhong Jianxin
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.
@@ -0,0 +1,29 @@
1
+ # Lknovel
2
+
3
+ Generate epub from http://lknovel.lightnovel.cn/
4
+
5
+ ## Installation
6
+
7
+ Install using gem:
8
+
9
+ $ gem install lknovel
10
+
11
+ Or add this line to your application's Gemfile:
12
+
13
+ gem 'lknovel'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ## Usage
20
+
21
+ $ lknovel http://lknovel.lightnovel.cn/main/book/2136.html
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/azuwis/lknovel/fork )
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
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ end
7
+
8
+ task :default => :test
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path('../../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'lknovel/app'
6
+
7
+ app = Lknovel::App.new(ARGV)
8
+ app.run
@@ -0,0 +1 @@
1
+ require "lknovel/volume"
@@ -0,0 +1,160 @@
1
+ require 'erb'
2
+ require 'fileutils'
3
+ require 'gepub'
4
+ require 'lknovel/volume'
5
+ require 'optparse'
6
+ require 'ostruct'
7
+ require 'pry'
8
+
9
+ module Lknovel
10
+ class App
11
+
12
+ def self.parse(args)
13
+ options = OpenStruct.new
14
+ options.verbose = true
15
+ options.keep = false
16
+
17
+ opt_parser = OptionParser.new do |opts|
18
+ opts.banner = 'Usage: lknovel [options] url'
19
+ opts.separator "\nSpecific options:"
20
+
21
+ opts.on('-k', '--[no-]keep', 'Keep temporary files') do |k|
22
+ options.keep = k
23
+ end
24
+
25
+ opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
26
+ options.verbose = v
27
+ end
28
+
29
+ opts.separator "\nCommon options:"
30
+
31
+ opts.on_tail('-h', '--help', 'Show this message') do
32
+ puts opts
33
+ exit
34
+ end
35
+
36
+ opts.on_tail('-V', '--version', 'Show version') do
37
+ puts VERSION
38
+ exit
39
+ end
40
+ end
41
+
42
+ begin
43
+ opt_parser.parse!(args)
44
+ rescue OptionParser::InvalidOption
45
+ puts opt_parser
46
+ exit
47
+ end
48
+
49
+ options
50
+ end
51
+
52
+ def initialize(args)
53
+ @options = self.class.parse(args)
54
+ begin
55
+ @console_width = `tput cols`.to_i
56
+ rescue Exception
57
+ @console_width = 80
58
+ end
59
+ end
60
+
61
+ def run
62
+ ARGV.each do |url|
63
+ process_volume(url)
64
+ end
65
+ end
66
+
67
+ def process_volume(url)
68
+ if @options.verbose
69
+ STDERR.write "Parsing chapters: ..."
70
+ end
71
+ volume = Volume.new(url) do |chapter|
72
+ if @options.verbose
73
+ STDERR.write "\r#{' ' * @console_width}"
74
+ STDERR.write "\rParsing chapters: #{chapter.title}"
75
+ end
76
+ end
77
+ if @options.verbose
78
+ puts
79
+ end
80
+
81
+ FileUtils.mkdir_p(volume.path)
82
+ Dir.chdir(volume.path) do
83
+ FileUtils.mkdir_p(IMAGE_DIR)
84
+ Dir.chdir(IMAGE_DIR) do
85
+ images = []
86
+ volume.chapters.each do |chapter|
87
+ chapter.content.each do |content|
88
+ images.push content if content.is_a?(Image)
89
+ end
90
+ end
91
+
92
+ if @options.verbose
93
+ progress = 1
94
+ end
95
+ STDERR.write "\rDownload images: 0/#{images.length}\t..."
96
+ Parallel.each(images, :in_threads => 5) do |image|
97
+ image.download
98
+ if @options.verbose
99
+ STDERR.write "\r#{' ' * @console_width}"
100
+ STDERR.write \
101
+ "\rDownload images: #{progress}/#{images.length}\t#{image.file}"
102
+ progress = progress + 1
103
+ end
104
+ end
105
+ if @options.verbose
106
+ puts
107
+ end
108
+
109
+ # crop cover image if width > height * 1.5
110
+ cropped = volume.cover_image.crop('cover.jpg',
111
+ '52%x100%+0+0') { |w, h| w > h * 1.5 }
112
+ volume.cover_image_cropped = 'cover.jpg' if cropped
113
+ end
114
+
115
+ FileUtils.mkdir_p(HTML_DIR)
116
+ Dir.chdir(HTML_DIR) do
117
+ volume.html(File.join(TEMPLATE_PATH, 'front.html.erb'), 'front.html')
118
+ erb = File.read(File.join(TEMPLATE_PATH, 'chapter.html.erb'))
119
+ template = ERB.new(erb, nil, '-')
120
+ volume.chapters.each_with_index do |chapter, index|
121
+ chapter.html(template, HTML_FILE_FORMAT % index)
122
+ end
123
+ end
124
+ end
125
+
126
+ builder = GEPUB::Builder.new {
127
+ unique_identifier volume.url
128
+ language 'zh'
129
+ date Time.parse(volume.date + ' +0800')
130
+
131
+ title "#{volume.series} - #{volume.number_s}"
132
+ collection volume.title, volume.number
133
+
134
+ creator volume.author
135
+ publisher volume.publisher
136
+ contributor volume.illustrator, 'ill'
137
+
138
+ resources(:workdir => volume.path) {
139
+ cover_image File.join(IMAGE_DIR, volume.cover_image_cropped)
140
+ file \
141
+ "#{STYLESHEET_DIR}/default.css" => "#{STYLESHEET_PATH}/default.css"
142
+ glob "#{IMAGE_DIR}/*"
143
+ ordered {
144
+ nav "#{HTML_DIR}/front.html"
145
+ volume.chapters.each_with_index do |chapter, index|
146
+ file "#{HTML_DIR}/#{HTML_FILE_FORMAT}" % index
147
+ heading chapter.title
148
+ end
149
+ }
150
+ }
151
+ }
152
+
153
+ builder.generate_epub("#{volume.path}.epub")
154
+ FileUtils.rm_r volume.path unless @options.keep
155
+ puts "Finish: #{volume.path}.epub"
156
+
157
+ end
158
+
159
+ end
160
+ end
@@ -0,0 +1,20 @@
1
+ h1, h2 {
2
+ text-align: center;
3
+ }
4
+
5
+ p {
6
+ text-indent: 2em;
7
+ line-height: 1.6em;
8
+ margin-top: 0.4em;
9
+ margin-bottom: 0.4em;
10
+ }
11
+
12
+ img {
13
+ display: block;
14
+ margin-left: auto;
15
+ margin-right: auto;
16
+ }
17
+
18
+ .page-break {
19
+ page-break-after: always;
20
+ }
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ require 'erb'
3
+ require 'fileutils'
4
+ require 'lknovel/image'
5
+ require 'lknovel/meta'
6
+ require 'lknovel/utils'
7
+ require 'nokogiri'
8
+ require 'open-uri'
9
+
10
+ module Lknovel
11
+ class Chapter
12
+
13
+ attr_reader :url, :title, :content
14
+
15
+ def initialize(url)
16
+ @url = url
17
+ parse
18
+ end
19
+
20
+ def parse
21
+ page = retryable do
22
+ Nokogiri::HTML(open(@url))
23
+ end
24
+
25
+ @title = page.css('li.active')[0].text.sub('章', '章 ').strip
26
+
27
+ @content = []
28
+ page.css('div#J_view').css('div.lk-view-line, br + br').each do |x|
29
+ img = x.css('img[data-cover]')
30
+ if x.name == 'br'
31
+ @content << ''
32
+ elsif img.length > 0
33
+ lk_image = Image.new(URI.join(url, img[0]['data-cover']))
34
+ @content << lk_image
35
+ else
36
+ # strip and remove leading wide space
37
+ @content << x.text.strip.sub(/^ +/, '')
38
+ end
39
+ end
40
+ end
41
+
42
+ def html(erb, path = nil)
43
+ template = erb.is_a?(ERB) ? erb : ERB.new(File.read(erb), nil, '-')
44
+ html_content = template.result(binding)
45
+ if path.nil?
46
+ html_content
47
+ else
48
+ if !File.exists?(path)
49
+ File.open(path, 'w') do |file|
50
+ file.puts html_content
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ require 'lknovel/utils'
2
+ require 'open-uri'
3
+ require 'uri'
4
+
5
+ module Lknovel
6
+ class Image
7
+
8
+ attr_reader :uri, :file
9
+
10
+ def initialize(url)
11
+ @uri = URI(url)
12
+ @file = @uri.path.split('/').last
13
+ end
14
+
15
+ def download(dir = '.')
16
+ file = File.join(dir, @file)
17
+ if !File.exists?(file)
18
+ File.open(file, 'wb') do |w|
19
+ retryable do
20
+ open(@uri, 'rb') do |r|
21
+ w.write(r.read)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def crop(output, operation, options = { :dir => '.' })
29
+ input = File.join(options[:dir], @file)
30
+ begin
31
+ dim = IO.popen(['identify', '-format', '%[fx:w] %[fx:h]', input])
32
+ dim = dim.gets.split
33
+ width = dim[0].to_i
34
+ height = dim[1].to_i
35
+ rescue Exception
36
+ width = 0
37
+ height = 0
38
+ end
39
+ need_crop = true
40
+ need_crop = yield(width, height) if block_given?
41
+ cropped = false
42
+ if need_crop
43
+ if system('convert', input, '-crop', operation, output)
44
+ cropped = true
45
+ end
46
+ end
47
+ cropped
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ module Lknovel
2
+ VERSION = "0.0.1"
3
+ MODULE_PATH = File.expand_path('..', __FILE__)
4
+ TEMPLATE_PATH = File.join(MODULE_PATH, 'templates')
5
+ STYLESHEET_PATH = File.join(MODULE_PATH, 'assets', 'stylesheets')
6
+ HTML_DIR = 'html'
7
+ IMAGE_DIR = 'images'
8
+ STYLESHEET_DIR = 'stylesheets'
9
+ HTML_FILE_FORMAT = '%03d.html'
10
+ end
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
4
+ <head>
5
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
6
+ <link href="<%= "../#{STYLESHEET_DIR}/default.css" %>" rel="stylesheet" type="text/css"/>
7
+ <title><%= @title %></title>
8
+ </head>
9
+ <body>
10
+ <h1><%= @title %></h1>
11
+ <% @content.each do |item| -%>
12
+ <% if item.is_a?(Image) -%>
13
+ <img src="<%= "../#{IMAGE_DIR}/#{item.file}" %>">
14
+ <% else -%>
15
+ <p><%= item %></p>
16
+ <% end -%>
17
+ <% end -%>
18
+ </body>
19
+ </html>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
5
+ <link href="<%= "../#{STYLESHEET_DIR}/default.css" %>" rel="stylesheet" type="text/css"/>
6
+ </head>
7
+ <body>
8
+ <img class="page-break" src="<%= "../#{IMAGE_DIR}/#{@cover_image_cropped}" %>">
9
+ <h1>简介</h1>
10
+ <p><%= @intro %></p>
11
+ <nav epub:type="toc" id="toc">
12
+ <ul class="nav">
13
+ <% @chapters.each_with_index do |chapter, index| -%>
14
+ <li><a href="<%= HTML_FILE_FORMAT % index %>"><%= chapter.title %></a></li>
15
+ <% end -%>
16
+ </ul>
17
+ </nav>
18
+ </body>
19
+ </html>
@@ -0,0 +1,24 @@
1
+ # http://blog.codefront.net/2008/01/14/retrying-code-blocks-in-ruby-on-exceptions-whatever/
2
+ # Options:
3
+ # * :tries - Number of retries to perform. Defaults to 3.
4
+ # * :on - The Exception on which a retry will be performed. Defaults to Exception, which retries on any Exception.
5
+ #
6
+ # Example
7
+ # =======
8
+ # retryable(:tries => 1, :on => OpenURI::HTTPError) do
9
+ # # your code here
10
+ # end
11
+
12
+ def retryable(options = {}, &block)
13
+ opts = { :tries => 3, :on => Exception }.merge(options)
14
+
15
+ retry_exception, retries = opts[:on], opts[:tries]
16
+
17
+ begin
18
+ return yield
19
+ rescue retry_exception
20
+ retry if (retries -= 1) > 0
21
+ end
22
+
23
+ yield
24
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+ require 'lknovel/chapter'
3
+ require 'lknovel/meta'
4
+ require 'lknovel/utils'
5
+ require 'nokogiri'
6
+ require 'open-uri'
7
+ require 'parallel'
8
+
9
+ module Lknovel
10
+ class Volume
11
+
12
+ attr_reader :url, :series, :author, :title, :number_s, :number, :date,
13
+ :illustrator, :publisher, :intro, :chapters, :path, :cover_image
14
+
15
+ attr_accessor :cover_image_cropped
16
+
17
+ def initialize(url, options = {}, &block)
18
+ @url = url
19
+ @options = {:threads => 4}.merge(options)
20
+ parse(&block)
21
+ end
22
+
23
+ def parse(&block)
24
+ page = retryable do
25
+ Nokogiri::HTML(open(@url))
26
+ end
27
+
28
+ page_title = page.title.split(' - ')
29
+ @series = page_title[0]
30
+ @number_s = page_title[1]
31
+ if /第(?<number>[.\d]+)卷/ =~ page_title[1]
32
+ @number = number.to_f
33
+ end
34
+
35
+ @intro = page.css('strong:contains("内容简介") + p').text
36
+
37
+ page.css('table.lk-book-detail td').each_slice(2) do |x|
38
+ case x[0].text
39
+ when /标 *题/
40
+ @title = x[1].text.strip
41
+ when /作 *者/
42
+ @author = x[1].text.strip
43
+ when /插 *画/
44
+ @illustrator = x[1].text.strip
45
+ when /文 *库/
46
+ @publisher = x[1].text.strip
47
+ when /更 *新/
48
+ @date = x[1].text.strip
49
+ end
50
+ end
51
+
52
+ @path = "#{@series} - #{@number_s} - #{@title}"
53
+
54
+ @chapters = Parallel.map(
55
+ page.css('ul.lk-chapter-list li.span3'),
56
+ :in_threads => @threads) do |x|
57
+ chapter_title = x.text.strip.sub(/\s+/, ' ')
58
+ chapter_url = URI.join(url, x.css('a')[0]['href']).to_s
59
+ chapter = Chapter.new(chapter_url)
60
+ block.call(chapter)
61
+ chapter
62
+ end
63
+
64
+ @cover_image = @chapters[0].content.find { |x| x.is_a?(Lknovel::Image) }
65
+ @cover_image_cropped = @cover_image.file
66
+ end
67
+
68
+ def html(erb, path = nil)
69
+ template = erb.is_a?(ERB) ? erb : ERB.new(File.read(erb), nil, '-')
70
+ html_content = template.result(binding)
71
+ if path.nil?
72
+ html_content
73
+ else
74
+ if !File.exists?(path)
75
+ File.open(path, 'w') do |file|
76
+ file.puts html_content
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lknovel/meta'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lknovel"
8
+ spec.version = Lknovel::VERSION
9
+ spec.authors = ["Zhong Jianxin"]
10
+ spec.email = ["azuwis@gmail.com"]
11
+ spec.summary = %q{Generate epub from http://lknovel.lightnovel.cn/}
12
+ spec.homepage = "https://github.com/azuwis/ruby-lknovel"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "minitest"
23
+
24
+ spec.add_runtime_dependency 'gepub'
25
+ spec.add_runtime_dependency 'nokogiri'
26
+ spec.add_runtime_dependency 'parallel'
27
+
28
+ spec.add_development_dependency 'pry-rescue'
29
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'minitest/autorun'
4
+ require 'pry-rescue/minitest'
@@ -0,0 +1 @@
1
+ require 'minitest_helper'
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ require 'minitest_helper'
3
+ require 'lknovel/chapter'
4
+
5
+ describe Lknovel::Chapter do
6
+
7
+ chapter = Lknovel::Chapter.new('http://lknovel.lightnovel.cn/main/view/1486.html')
8
+
9
+ it 'get chapter title' do
10
+ chapter.title.must_equal '第0章 序章'
11
+ end
12
+
13
+ it 'get chapter text' do
14
+ chapter.content.must_include '变态王子与不笑猫'
15
+ end
16
+
17
+ it 'get chapter image' do
18
+ chapter.content.find{|x| x.is_a? Lknovel::Image}.file.must_equal '20120808202600_62961.jpg'
19
+ end
20
+
21
+ it 'generate html' do
22
+ html = chapter.html(File.join(Lknovel::TEMPLATE_PATH, 'chapter.html.erb'))
23
+ html.must_match '"../stylesheets/default.css"'
24
+ html.must_match '"../images/20120808202639_66681.jpg"'
25
+ end
26
+
27
+ end
@@ -0,0 +1,28 @@
1
+ require 'minitest_helper'
2
+ require 'lknovel/image'
3
+
4
+ describe Lknovel::Image do
5
+
6
+ TMP = 'test/tmp'
7
+
8
+ FileUtils.mkdir_p TMP
9
+
10
+ image = Lknovel::Image.new('http://lknovel.lightnovel.cn/illustration/image/20120808/20120808202600_62961.jpg')
11
+
12
+ it '@file' do
13
+ image.file.must_equal '20120808202600_62961.jpg'
14
+ end
15
+
16
+ it 'download' do
17
+ image.download(TMP)
18
+ File.exists?(File.join(TMP, image.file)).must_equal true
19
+ end
20
+
21
+ it 'crop' do
22
+ cover_image = File.join(TMP, 'cover.jpg')
23
+ cropped = image.crop(cover_image, '52%x100%+0+0', :dir => TMP) { |w, h| w > h * 1.5 }
24
+ cropped.must_equal true
25
+ File.exists?(cover_image).must_equal true
26
+ end
27
+
28
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ require 'minitest_helper'
3
+ require 'lknovel/volume'
4
+
5
+ describe Lknovel::Volume do
6
+
7
+ volume = Lknovel::Volume.new('http://lknovel.lightnovel.cn/main/book/2136.html')
8
+
9
+ it 'get path' do
10
+ volume.path.must_equal '打工吧!魔王大人 - 短篇01 - 短篇01'
11
+ end
12
+
13
+ it 'get author' do
14
+ volume.author.must_equal '和原聪司'
15
+ end
16
+
17
+ it 'get illustrator' do
18
+ volume.illustrator.must_equal '029'
19
+ end
20
+
21
+ it 'get publisher' do
22
+ volume.publisher.must_equal '电击文库'
23
+ end
24
+
25
+ it 'get date' do
26
+ volume.date.must_equal '2012-08-17 21:02:34'
27
+ end
28
+
29
+ it 'get intro' do
30
+ volume.intro.must_match /『拼死工作吧!魔王陛下!』/
31
+ end
32
+
33
+ it 'get cover image' do
34
+ volume.cover_image.file.must_equal '20120817210516_51962.jpg'
35
+ end
36
+
37
+ it 'generate front html' do
38
+ html = volume.html(File.join(Lknovel::TEMPLATE_PATH, 'front.html.erb'))
39
+ html.must_match '<li><a href="000.html">第0章 序章</a></li>'
40
+ end
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lknovel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Zhong Jianxin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-03-17 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.5'
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.5'
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: minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
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: gepub
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: nokogiri
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: parallel
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
+ - !ruby/object:Gem::Dependency
111
+ name: pry-rescue
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description:
127
+ email:
128
+ - azuwis@gmail.com
129
+ executables:
130
+ - lknovel
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - .gitignore
135
+ - .travis.yml
136
+ - CHANGELOG
137
+ - Gemfile
138
+ - LICENSE.txt
139
+ - README.md
140
+ - Rakefile
141
+ - bin/lknovel
142
+ - lib/lknovel.rb
143
+ - lib/lknovel/app.rb
144
+ - lib/lknovel/assets/stylesheets/default.css
145
+ - lib/lknovel/chapter.rb
146
+ - lib/lknovel/image.rb
147
+ - lib/lknovel/meta.rb
148
+ - lib/lknovel/templates/chapter.html.erb
149
+ - lib/lknovel/templates/front.html.erb
150
+ - lib/lknovel/utils.rb
151
+ - lib/lknovel/volume.rb
152
+ - lknovel.gemspec
153
+ - test/minitest_helper.rb
154
+ - test/test_lknovel.rb
155
+ - test/test_lknovel_chapter.rb
156
+ - test/test_lknovel_image.rb
157
+ - test/test_lknovel_volume.rb
158
+ homepage: https://github.com/azuwis/ruby-lknovel
159
+ licenses:
160
+ - MIT
161
+ post_install_message:
162
+ rdoc_options: []
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ! '>='
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ! '>='
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 1.8.23
180
+ signing_key:
181
+ specification_version: 3
182
+ summary: Generate epub from http://lknovel.lightnovel.cn/
183
+ test_files:
184
+ - test/minitest_helper.rb
185
+ - test/test_lknovel.rb
186
+ - test/test_lknovel_chapter.rb
187
+ - test/test_lknovel_image.rb
188
+ - test/test_lknovel_volume.rb
189
+ has_rdoc: