ebookbinder 1.0.0
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.
- checksums.yaml +7 -0
- data/Changelog +2 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +30 -0
- data/Rakefile +14 -0
- data/ebookbinder.gemspec +26 -0
- data/lib/ebookbinder/ebook_base.rb +47 -0
- data/lib/ebookbinder/epub2.rb +147 -0
- data/lib/ebookbinder/epub3.rb +142 -0
- data/lib/ebookbinder/epub_base.rb +71 -0
- data/lib/ebookbinder/version.rb +7 -0
- data/lib/ebookbinder.rb +37 -0
- data/test/epub2/Rakefile +6 -0
- data/test/epub2/src/01.xhtml +15 -0
- data/test/epub2/src/02.xhtml +16 -0
- data/test/epub3/Rakefile +6 -0
- data/test/epub3/src/01.xhtml +14 -0
- data/test/epub3/src/02.xhtml +15 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e84bb03efbd7cc1485383c90b47e60fbe9e61f711b5dcd19f016372433c08b00
|
4
|
+
data.tar.gz: 43a1abc9fde8c47f9d8cd50f8829f490f249381240bbf7e772a7d7377c7d92c3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: be92f5553c6ff6417c4d2bafe8e8b487cbc9084f7721f647e8de787d354c9816a3dd81a44bf322231de57c84881a42a084b0d7460764dd622436842edc4cac30
|
7
|
+
data.tar.gz: 388f22704f7770c26881542c3fe53d97ef58a5cd9e851e74382441ce26dca73c599048532b06ec704f60caee3e1202bd6ee2479fcbd05793cb20f6c3685667f3
|
data/Changelog
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2015, 2017, 2024 Jan Friedrich
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Ebookbinder
|
2
|
+
|
3
|
+
|
4
|
+
## Description
|
5
|
+
|
6
|
+
This library should help to make ebooks as easy as possible. It interprets an
|
7
|
+
XHTML structure and generate a corresponding ebook on base of easy asumptions.
|
8
|
+
|
9
|
+
|
10
|
+
## Requirements
|
11
|
+
|
12
|
+
To use rake check it needs an actual version of
|
13
|
+
[epubcheck](https://www.w3.org/publishing/epubcheck/) accessible on the
|
14
|
+
commandline via `epubcheck`.
|
15
|
+
|
16
|
+
|
17
|
+
## Versioning
|
18
|
+
|
19
|
+
Ebookbinder follows [Semantic Versioning](https://semver.org/), both SemVer and
|
20
|
+
SemVerTag.
|
21
|
+
|
22
|
+
|
23
|
+
## Author
|
24
|
+
|
25
|
+
Jan Friedrich <janfri26@gmail.com>
|
26
|
+
|
27
|
+
|
28
|
+
## MIT License
|
29
|
+
|
30
|
+
See file LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rim/tire'
|
4
|
+
require 'rim/version'
|
5
|
+
require_relative 'lib/ebookbinder/version'
|
6
|
+
|
7
|
+
Rim.setup do |r|
|
8
|
+
r.name = 'ebookbinder'
|
9
|
+
r.authors = 'Jan Friedrich'
|
10
|
+
r.email = 'janfri26@gmail.com'
|
11
|
+
r.version = Ebookbinder::VERSION
|
12
|
+
r.gem_files.exclude(/build/).exclude {|e| File.directory?(e)}
|
13
|
+
r.test_files = FileList.new()
|
14
|
+
end
|
data/ebookbinder.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: ebookbinder 1.0.0 ruby lib
|
3
|
+
#
|
4
|
+
# This file is automatically generated by rim.
|
5
|
+
# PLEASE DO NOT EDIT IT DIRECTLY!
|
6
|
+
# Change the values in Rim.setup in Rakefile instead.
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "ebookbinder"
|
10
|
+
s.version = "1.0.0"
|
11
|
+
|
12
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
s.authors = ["Jan Friedrich"]
|
15
|
+
s.date = "2024-03-02"
|
16
|
+
s.description = ""
|
17
|
+
s.email = "janfri26@gmail.com"
|
18
|
+
s.files = ["Changelog", "Gemfile", "LICENSE", "README.md", "Rakefile", "ebookbinder.gemspec", "lib/ebookbinder.rb", "lib/ebookbinder/ebook_base.rb", "lib/ebookbinder/epub2.rb", "lib/ebookbinder/epub3.rb", "lib/ebookbinder/epub_base.rb", "lib/ebookbinder/version.rb", "test/epub2/Rakefile", "test/epub2/src/01.xhtml", "test/epub2/src/02.xhtml", "test/epub3/Rakefile", "test/epub3/src/01.xhtml", "test/epub3/src/02.xhtml"]
|
19
|
+
s.rubygems_version = "3.6.0.dev"
|
20
|
+
s.summary = ""
|
21
|
+
|
22
|
+
s.specification_version = 4
|
23
|
+
|
24
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
25
|
+
s.add_development_dependency(%q<rim>, ["~> 2.17"])
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative '../ebookbinder'
|
3
|
+
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
module Ebookbinder
|
8
|
+
|
9
|
+
class EbookBase
|
10
|
+
|
11
|
+
include Singleton
|
12
|
+
include Rake::DSL
|
13
|
+
|
14
|
+
attr_accessor :author, :id, :language, :title
|
15
|
+
attr_accessor :build_dir, :src_dir
|
16
|
+
attr_accessor :task_defs
|
17
|
+
|
18
|
+
def self.setup
|
19
|
+
instance.setup do |i|
|
20
|
+
yield i
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.define_tasks &blk
|
25
|
+
instance.task_defs ||= []
|
26
|
+
instance.task_defs << blk
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup
|
30
|
+
yield self
|
31
|
+
check_mandatory_values
|
32
|
+
set_defaults
|
33
|
+
define_tasks
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def define_tasks
|
40
|
+
Array(@task_defs).each do |blk|
|
41
|
+
instance_exec &blk
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative 'epub_base'
|
3
|
+
|
4
|
+
module Ebookbinder
|
5
|
+
|
6
|
+
class Epub2 < EpubBase
|
7
|
+
|
8
|
+
def set_defaults
|
9
|
+
@id ||= Digest::MD5.hexdigest(@title)
|
10
|
+
@language ||= 'en'
|
11
|
+
@src_dir ||= 'src'
|
12
|
+
@build_dir ||= 'build'
|
13
|
+
@epub_dir ||= File.join(@build_dir, 'epub2')
|
14
|
+
@meta_inf_dir = File.join(@epub_dir, 'META-INF')
|
15
|
+
@epub_filename ||= File.join(@build_dir, format('%s - %s.epub', @author, @title))
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_content_file
|
19
|
+
puts "generate #{content_filename}" if verbose
|
20
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
21
|
+
xml.package(xmlns: "http://www.idpf.org/2007/opf", 'unique-identifier': 'pub-id', version: '2.0') do
|
22
|
+
xml.metadata('xmlns:dc': 'http://purl.org/dc/elements/1.1/', 'xmlns:dcterms': 'http://purl.org/dc/terms/',
|
23
|
+
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:opf': 'http://www.idpf.org/2007/opf') do
|
24
|
+
xml['dc'].identifier(id, id: 'pub-id')
|
25
|
+
xml['dc'].title title
|
26
|
+
xml['dc'].creator(@author, 'xml:lang' => language)
|
27
|
+
xml['dc'].language language, 'xsi:type' => 'dcterms:RFC3066'
|
28
|
+
end
|
29
|
+
xml.manifest do
|
30
|
+
i = 0
|
31
|
+
content_filenames.each do |fn|
|
32
|
+
i += 1
|
33
|
+
xml.item(id: format('id_%04d', i), href: href(fn), 'media-type' => Ebookbinder.mimetype_for_filename(fn))
|
34
|
+
end
|
35
|
+
xml.item(id: 'ncx', href: href(ncx_filename), 'media-type' => 'application/x-dtbncx+xml')
|
36
|
+
end
|
37
|
+
xml.spine toc: 'ncx' do
|
38
|
+
i = 0
|
39
|
+
content_filenames.each do |fn|
|
40
|
+
i += 1
|
41
|
+
next unless Ebookbinder.mimetype_for_filename(fn) == 'application/xhtml+xml'
|
42
|
+
xml.itemref(idref: format('id_%04d', i))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
File.write(content_filename, builder.to_xml)
|
48
|
+
end
|
49
|
+
|
50
|
+
def ncx_filename
|
51
|
+
File.join(@epub_dir, 'toc.ncx')
|
52
|
+
end
|
53
|
+
|
54
|
+
def generate_ncx_file
|
55
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
56
|
+
xml.ncx(xmlns: 'http://www.daisy.org/z3986/2005/ncx/', version: '2005-1') do
|
57
|
+
xml.head do
|
58
|
+
xml.meta name: 'dtb:uid', content: id
|
59
|
+
xml.meta name: 'dtb:depth', content: '2'
|
60
|
+
xml.meta name: 'dtb:totalPageCount', content: '0'
|
61
|
+
xml.meta name: 'dtb:maxPageNumber', content: '0'
|
62
|
+
end
|
63
|
+
xml.docTitle do
|
64
|
+
xml.text! title
|
65
|
+
end
|
66
|
+
xml.navMap do
|
67
|
+
i = 0
|
68
|
+
content_filenames.each do |fn|
|
69
|
+
next unless Ebookbinder.mimetype_for_filename(fn) == 'application/xhtml+xml'
|
70
|
+
Nokogiri.XML(File.read(fn)).search('h1').each do |e|
|
71
|
+
if id = e.attribute('id')
|
72
|
+
i +=1
|
73
|
+
xml.navPoint id: format('id_%04d', i), playOrder: i do
|
74
|
+
xml.navLabel do
|
75
|
+
xml.text! e.text
|
76
|
+
end
|
77
|
+
xml.content src: href(fn, id)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
File.write(ncx_filename, builder.to_xml)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
Epub2.define_tasks do
|
91
|
+
|
92
|
+
::CLEAN << epub_dir
|
93
|
+
::CLOBBER << build_dir << epub_filename
|
94
|
+
|
95
|
+
namespace :epub2 do
|
96
|
+
|
97
|
+
directory build_dir
|
98
|
+
directory epub_dir
|
99
|
+
directory meta_inf_dir
|
100
|
+
|
101
|
+
content_filenames.zip(source_filenames) do |cf, sf|
|
102
|
+
td = File.dirname(cf)
|
103
|
+
directory td
|
104
|
+
file cf => [td, sf] do
|
105
|
+
cp sf, cf
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
file mimetype_filename => epub_dir do
|
110
|
+
generate_mimetype_file
|
111
|
+
end
|
112
|
+
|
113
|
+
file container_filename => meta_inf_dir do
|
114
|
+
generate_container_file
|
115
|
+
end
|
116
|
+
|
117
|
+
file content_filename => [epub_dir, content_filenames].flatten do
|
118
|
+
generate_content_file
|
119
|
+
end
|
120
|
+
|
121
|
+
file ncx_filename => [epub_dir, content_filenames].flatten do
|
122
|
+
generate_ncx_file
|
123
|
+
end
|
124
|
+
|
125
|
+
all_filenames = [mimetype_filename, container_filename, content_filenames, content_filename, ncx_filename].flatten
|
126
|
+
|
127
|
+
file epub_filename => all_filenames do
|
128
|
+
root = Dir.pwd
|
129
|
+
epub_filename_fullpath = File.join(root, epub_filename)
|
130
|
+
cd epub_dir do
|
131
|
+
sh "zip -Xr9D \"#{epub_filename_fullpath}\" mimetype *"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
task :build => epub_filename
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
task :build => 'epub2:build'
|
140
|
+
|
141
|
+
task :check => epub_filename do
|
142
|
+
sh 'epubcheck', epub_filename
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative 'epub_base'
|
3
|
+
|
4
|
+
module Ebookbinder
|
5
|
+
|
6
|
+
class Epub3 < EpubBase
|
7
|
+
|
8
|
+
def set_defaults
|
9
|
+
@id ||= Digest::MD5.hexdigest(@title)
|
10
|
+
@language ||= 'en'
|
11
|
+
@src_dir ||= 'src'
|
12
|
+
@build_dir ||= 'build'
|
13
|
+
@epub_dir ||= File.join(@build_dir, 'epub3')
|
14
|
+
@meta_inf_dir = File.join(@epub_dir, 'META-INF')
|
15
|
+
@epub_filename ||= File.join(@build_dir, format('%s - %s.epub', @author, @title))
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_content_file
|
19
|
+
puts "generate #{content_filename}" if verbose
|
20
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
21
|
+
xml.package(xmlns: "http://www.idpf.org/2007/opf", 'unique-identifier': 'pub-id', version: '3.0', 'xml:lang': language) do
|
22
|
+
xml.metadata('xmlns:dc': 'http://purl.org/dc/elements/1.1/', 'xmlns:dcterms': 'http://purl.org/dc/terms/',
|
23
|
+
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:opf': 'http://www.idpf.org/2007/opf') do
|
24
|
+
xml['dc'].identifier(id, id: 'pub-id')
|
25
|
+
xml['dc'].title title
|
26
|
+
xml['dc'].creator(@author, 'xml:lang' => language)
|
27
|
+
xml['dc'].language language
|
28
|
+
xml.meta(Time.now.utc.to_datetime.to_s.sub(/\+00:00$/, 'Z'), property: 'dcterms:modified')
|
29
|
+
end
|
30
|
+
xml.manifest do
|
31
|
+
i = 0
|
32
|
+
content_filenames.each do |fn|
|
33
|
+
i += 1
|
34
|
+
xml.item(id: format('id_%04d', i), href: href(fn), 'media-type' => Ebookbinder.mimetype_for_filename(fn))
|
35
|
+
end
|
36
|
+
xml.item(id: 'nav', href: href(nav_filename), 'media-type' => Ebookbinder.mimetype_for_filename(nav_filename), properties: 'nav')
|
37
|
+
end
|
38
|
+
xml.spine do
|
39
|
+
i = 0
|
40
|
+
content_filenames.each do |fn|
|
41
|
+
i += 1
|
42
|
+
next unless Ebookbinder.mimetype_for_filename(fn) == 'application/xhtml+xml'
|
43
|
+
xml.itemref(idref: format('id_%04d', i))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
File.write(content_filename, builder.to_xml)
|
49
|
+
end
|
50
|
+
|
51
|
+
def nav_filename
|
52
|
+
File.join(@epub_dir, 'nav.xhtml')
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_nav_file
|
56
|
+
puts "generate #{nav_filename}"
|
57
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
58
|
+
xml.html(xmlns: 'http://www.w3.org/1999/xhtml') do
|
59
|
+
xml.head do
|
60
|
+
xml.title @title
|
61
|
+
end
|
62
|
+
xml.body do
|
63
|
+
xml.nav('xmlns:epub' => 'http://www.idpf.org/2007/ops', 'epub:type' => 'toc', id: 'toc') do
|
64
|
+
xml.ol do
|
65
|
+
content_filenames.each do |fn|
|
66
|
+
next unless Ebookbinder.mimetype_for_filename(fn) == 'application/xhtml+xml'
|
67
|
+
Nokogiri.XML(File.read(fn)).search('h1').each do |e|
|
68
|
+
if id = e.attribute('id')
|
69
|
+
xml.li do
|
70
|
+
xml.a(e.text, href: href(fn, id))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
File.write(nav_filename, builder.to_xml)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
Epub3.define_tasks do
|
86
|
+
|
87
|
+
::CLEAN << epub_dir
|
88
|
+
::CLOBBER << build_dir << epub_filename
|
89
|
+
|
90
|
+
namespace :epub3 do
|
91
|
+
|
92
|
+
directory build_dir
|
93
|
+
directory epub_dir
|
94
|
+
directory meta_inf_dir
|
95
|
+
|
96
|
+
content_filenames.zip(source_filenames) do |cf, sf|
|
97
|
+
td = File.dirname(cf)
|
98
|
+
directory td
|
99
|
+
file cf => [td, sf] do
|
100
|
+
cp sf, cf
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
file mimetype_filename => epub_dir do
|
105
|
+
generate_mimetype_file
|
106
|
+
end
|
107
|
+
|
108
|
+
file container_filename => meta_inf_dir do
|
109
|
+
generate_container_file
|
110
|
+
end
|
111
|
+
|
112
|
+
file content_filename => [epub_dir, content_filenames].flatten do
|
113
|
+
generate_content_file
|
114
|
+
end
|
115
|
+
|
116
|
+
file nav_filename => [epub_dir, content_filenames].flatten do
|
117
|
+
generate_nav_file
|
118
|
+
end
|
119
|
+
|
120
|
+
all_filenames = [mimetype_filename, container_filename, content_filenames, content_filename, nav_filename].flatten
|
121
|
+
|
122
|
+
file epub_filename => all_filenames do
|
123
|
+
root = Dir.pwd
|
124
|
+
epub_filename_fullpath = File.join(root, epub_filename)
|
125
|
+
cd epub_dir do
|
126
|
+
sh "zip -Xr9D \"#{epub_filename_fullpath}\" mimetype *"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
task :build => epub_filename
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
task :build => 'epub3:build'
|
135
|
+
|
136
|
+
task :check => epub_filename do
|
137
|
+
sh 'epubcheck', epub_filename
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative 'ebook_base'
|
3
|
+
|
4
|
+
require 'date'
|
5
|
+
require 'digest/md5'
|
6
|
+
require 'nokogiri'
|
7
|
+
|
8
|
+
module Ebookbinder
|
9
|
+
|
10
|
+
class EpubBase < EbookBase
|
11
|
+
|
12
|
+
attr_accessor :epub_filename
|
13
|
+
attr_reader :epub_dir, :meta_inf_dir, :mimetype_filename, :nav_filename
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def check_mandatory_values
|
18
|
+
%w(title author).each do |attr|
|
19
|
+
unless self.send(attr)
|
20
|
+
raise format('No value for %s given!', attr)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def mimetype_filename
|
26
|
+
File.join(@epub_dir, 'mimetype')
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_mimetype_file
|
30
|
+
puts "generate #{mimetype_filename}" if verbose
|
31
|
+
File.write(mimetype_filename, 'application/epub+zip')
|
32
|
+
end
|
33
|
+
|
34
|
+
def container_filename
|
35
|
+
File.join(@meta_inf_dir, 'container.xml')
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_container_file
|
39
|
+
puts "generate #{container_filename}" if verbose
|
40
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
41
|
+
xml.container(version: '1.0', xmlns: 'urn:oasis:names:tc:opendocument:xmlns:container') do
|
42
|
+
xml.rootfiles do
|
43
|
+
xml.rootfile('full-path': content_filename.sub(%r(^#{epub_dir}/?), ''), 'media-type': 'application/oebps-package+xml')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
File.write(container_filename, builder.to_xml)
|
48
|
+
end
|
49
|
+
|
50
|
+
def content_filename
|
51
|
+
File.join(@epub_dir, 'content.opf')
|
52
|
+
end
|
53
|
+
|
54
|
+
def content_filenames
|
55
|
+
source_filenames.sub(/^#{src_dir}/, epub_dir)
|
56
|
+
end
|
57
|
+
|
58
|
+
def source_filenames
|
59
|
+
FileList.new(File.join(src_dir, '**/*')).select {|fn| !File.directory?(fn)}.sort
|
60
|
+
end
|
61
|
+
|
62
|
+
def href filename, id=nil
|
63
|
+
res = filename.sub(%r(^#{epub_dir}/?), '')
|
64
|
+
res << '#' << id.to_s if id
|
65
|
+
res
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
data/lib/ebookbinder.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rake'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Ebookbinder
|
6
|
+
|
7
|
+
MIMETYPE_MAPPING = YAML.load <<-END
|
8
|
+
css: text/css
|
9
|
+
gif: image/gif
|
10
|
+
htm: text/html
|
11
|
+
html: text/html
|
12
|
+
jpe: image/jpeg
|
13
|
+
jpeg: image/jpeg
|
14
|
+
jpg: image/jpeg
|
15
|
+
png: image/png
|
16
|
+
svg: image/svg+xml
|
17
|
+
svgz: image/svg+xml
|
18
|
+
ttc: application/x-font-ttf
|
19
|
+
ttf: application/x-font-ttf
|
20
|
+
xhtml: application/xhtml+xml
|
21
|
+
END
|
22
|
+
|
23
|
+
def self.mimetype_for_filename fn
|
24
|
+
MIMETYPE_MAPPING[File.extname(fn).sub(/^\./, '')] or raise "Unknown mimetype for file #{fn}!"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
include Ebookbinder
|
30
|
+
|
31
|
+
desc 'Build ebook file(s)'
|
32
|
+
task :build
|
33
|
+
|
34
|
+
desc 'Check ebook file(s)'
|
35
|
+
task :check
|
36
|
+
|
37
|
+
task :default => :build
|
data/test/epub2/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
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="de">
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/>
|
6
|
+
<title>Title 01</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<h1 id="id1">H1 number 1</h1>
|
10
|
+
<h1 id="id2">H1 number 2</h1>
|
11
|
+
<h1 id="id3">H1 number 3</h1>
|
12
|
+
<h1 id="id4">H1 number 4</h1>
|
13
|
+
<h1 id="id5">H1 number 5</h1>
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -0,0 +1,16 @@
|
|
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="de">
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/>
|
6
|
+
<title>Title 02</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<h1 id="id1">H1 number 1</h1>
|
10
|
+
<h1 id="id2">H1 number 2</h1>
|
11
|
+
<h1 id="id3">H1 number 3</h1>
|
12
|
+
<h1 id="id4">H1 number 4</h1>
|
13
|
+
<h1 id="id5">H1 number 5</h1>
|
14
|
+
</body>
|
15
|
+
</html>
|
16
|
+
|
data/test/epub3/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html>
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<title>Title 01</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1 id="id1">H1 number 1</h1>
|
9
|
+
<h1 id="id2">H1 number 2</h1>
|
10
|
+
<h1 id="id3">H1 number 3</h1>
|
11
|
+
<h1 id="id4">H1 number 4</h1>
|
12
|
+
<h1 id="id5">H1 number 5</h1>
|
13
|
+
</body>
|
14
|
+
</html>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html>
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<title>Title 02</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1 id="id1">H1 number 1</h1>
|
9
|
+
<h1 id="id2">H1 number 2</h1>
|
10
|
+
<h1 id="id3">H1 number 3</h1>
|
11
|
+
<h1 id="id4">H1 number 4</h1>
|
12
|
+
<h1 id="id5">H1 number 5</h1>
|
13
|
+
</body>
|
14
|
+
</html>
|
15
|
+
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ebookbinder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Friedrich
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2024-03-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: rake
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :development
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rim
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.17'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.17'
|
40
|
+
description: ''
|
41
|
+
email: janfri26@gmail.com
|
42
|
+
executables: []
|
43
|
+
extensions: []
|
44
|
+
extra_rdoc_files: []
|
45
|
+
files:
|
46
|
+
- Changelog
|
47
|
+
- Gemfile
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- ebookbinder.gemspec
|
52
|
+
- lib/ebookbinder.rb
|
53
|
+
- lib/ebookbinder/ebook_base.rb
|
54
|
+
- lib/ebookbinder/epub2.rb
|
55
|
+
- lib/ebookbinder/epub3.rb
|
56
|
+
- lib/ebookbinder/epub_base.rb
|
57
|
+
- lib/ebookbinder/version.rb
|
58
|
+
- test/epub2/Rakefile
|
59
|
+
- test/epub2/src/01.xhtml
|
60
|
+
- test/epub2/src/02.xhtml
|
61
|
+
- test/epub3/Rakefile
|
62
|
+
- test/epub3/src/01.xhtml
|
63
|
+
- test/epub3/src/02.xhtml
|
64
|
+
licenses: []
|
65
|
+
metadata: {}
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubygems_version: 3.6.0.dev
|
81
|
+
specification_version: 4
|
82
|
+
summary: ''
|
83
|
+
test_files: []
|