lknovel 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.
@@ -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: