publishr 0.5.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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/bin/publishr +53 -0
- data/lib/epub_skeleton/META-INF/container.xml +6 -0
- data/lib/epub_skeleton/epub.css +90 -0
- data/lib/epub_skeleton/mimetype +1 -0
- data/lib/epub_templates/content.opf.erb +33 -0
- data/lib/epub_templates/kramdown.html +11 -0
- data/lib/epub_templates/manifest_items.erb +1 -0
- data/lib/epub_templates/nav_points.erb +6 -0
- data/lib/epub_templates/spine_items.erb +1 -0
- data/lib/epub_templates/toc.ncx.erb +21 -0
- data/lib/publishr.rb +27 -0
- data/lib/publishr/epub_renderer.rb +128 -0
- data/lib/publishr/latex_processor.rb +85 -0
- data/lib/publishr/latex_renderer.rb +54 -0
- data/lib/publishr/markup_processor.rb +95 -0
- data/lib/publishr/project.rb +66 -0
- data/lib/publishr/version.rb +3 -0
- data/publishr.gemspec +24 -0
- metadata +67 -0
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/publishr
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# PublishR -- Fast publishing for ebooks and paper
|
4
|
+
# Copyright (C) 2012 Michael Franzl
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as
|
8
|
+
# published by the Free Software Foundation, either version 3 of the
|
9
|
+
# License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
21
|
+
|
22
|
+
require 'publishr'
|
23
|
+
|
24
|
+
if ARGV[0].nil?
|
25
|
+
puts ''
|
26
|
+
puts 'PublishR -- Fast publishing for ebooks and paper'
|
27
|
+
puts 'Copyright (C) 2012 Michael Franzl'
|
28
|
+
puts ''
|
29
|
+
puts ''
|
30
|
+
puts "USAGE: publishr [name] [path_to_source_dir] [format] [path_to_converters]"
|
31
|
+
puts ''
|
32
|
+
puts " [name] is an unique string that identifies your project. Rendered files will be named after this."
|
33
|
+
puts " [path_to_source_dir] directory must minimally contain: [cover.jpg, covertext.txt, frontmatter.txt, toc.txt, metadata.yml]"
|
34
|
+
puts " [format] must be {mobi, epub, pdf}"
|
35
|
+
puts " [path_to_converters] directory must contain `kindlegen` and `jpg2ps`. They cannot be shipped with this program due to legal reasons."
|
36
|
+
puts ''
|
37
|
+
puts 'EXAMPLE: publishr mybook1 my/files/mybook epub path/to/converters'
|
38
|
+
puts ''
|
39
|
+
puts 'This program is free software: you can redistribute it and/or modify'
|
40
|
+
puts 'it under the terms of the GNU Affero General Public License as'
|
41
|
+
puts 'published by the Free Software Foundation, either version 3 of the'
|
42
|
+
puts 'License, or (at your option) any later version.'
|
43
|
+
puts ''
|
44
|
+
puts ''
|
45
|
+
Process.exit
|
46
|
+
end
|
47
|
+
|
48
|
+
project = Publishr::Project.new(ARGV[0], ARGV[1], ARGV[3])
|
49
|
+
|
50
|
+
case ARGV[2]
|
51
|
+
when 'kindle' then project.make_kindle
|
52
|
+
when 'pdf' then project.make_pdf
|
53
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
p {
|
2
|
+
margin-bottom: 1em;
|
3
|
+
font-size: medium;
|
4
|
+
}
|
5
|
+
|
6
|
+
.blockquote_transcript_1 {
|
7
|
+
margin-left: 1em;
|
8
|
+
font-size: small;
|
9
|
+
}
|
10
|
+
|
11
|
+
.blockquote__1 {
|
12
|
+
margin-left: 1em;
|
13
|
+
font-size: small;
|
14
|
+
}
|
15
|
+
|
16
|
+
.blockquote_email_1 {
|
17
|
+
margin-left: 1em;
|
18
|
+
font-size: xx-small;
|
19
|
+
font-family: Monospace;
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
.blockquote_transcript_2 {
|
24
|
+
margin-left: 1em;
|
25
|
+
font-size: small;
|
26
|
+
font-style: italic;
|
27
|
+
}
|
28
|
+
|
29
|
+
.blockquote__2 {
|
30
|
+
margin-left: 1em;
|
31
|
+
font-size: small;
|
32
|
+
font-style: italic;
|
33
|
+
}
|
34
|
+
|
35
|
+
.blockquote_email_2 {
|
36
|
+
margin-left: 1em;
|
37
|
+
font-size: xx-small;
|
38
|
+
font-style: italic;
|
39
|
+
font-family: Monospace;
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
code {
|
44
|
+
font-style: italic;
|
45
|
+
font-size: small;
|
46
|
+
}
|
47
|
+
|
48
|
+
.image {
|
49
|
+
text-align: center;
|
50
|
+
}
|
51
|
+
|
52
|
+
h1 {
|
53
|
+
margin-bottom: 1em;
|
54
|
+
margin-top: 2em;
|
55
|
+
font-size: xx-large;
|
56
|
+
text-align: center;
|
57
|
+
}
|
58
|
+
|
59
|
+
h2 {
|
60
|
+
margin-bottom: 2em;
|
61
|
+
text-align: center;
|
62
|
+
}
|
63
|
+
|
64
|
+
h3 {
|
65
|
+
margin-bottom: 1em;
|
66
|
+
margin-top: 1em;
|
67
|
+
text-align: center;
|
68
|
+
}
|
69
|
+
|
70
|
+
.covertext {
|
71
|
+
text-align: center;
|
72
|
+
font-size: xx-small;
|
73
|
+
}
|
74
|
+
|
75
|
+
.copyright {
|
76
|
+
font-size: xx-small;
|
77
|
+
text-indent: 0;
|
78
|
+
}
|
79
|
+
|
80
|
+
.title {
|
81
|
+
text-align: center;
|
82
|
+
}
|
83
|
+
|
84
|
+
.footnote {
|
85
|
+
font-size: x-small;
|
86
|
+
}
|
87
|
+
|
88
|
+
.toc {
|
89
|
+
text-indent: 0;
|
90
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
application/epub+zip
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
|
3
|
+
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="<%= @metadata['identifier'] %>">
|
4
|
+
|
5
|
+
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:opf="http://www.idpf.org/2007/opf">
|
6
|
+
<dc:title><%= @metadata['title'] %></dc:title>
|
7
|
+
<dc:language xsi:type="dcterms:RFC3066"><%= @metadata['language'] %></dc:language>
|
8
|
+
<meta name="cover" content="coverjpg" />
|
9
|
+
<dc:identifier id="<%= @metadata['identifier'] %>" opf:scheme="ISBN"><%= @metadata['isbn'] %></dc:identifier>
|
10
|
+
<dc:creator><%= @metadata['creator'] %></dc:creator>
|
11
|
+
<dc:publisher><%= @metadata['publisher'] %></dc:publisher>
|
12
|
+
<dc:subject><%= @metadata['subject'] %></dc:subject>
|
13
|
+
<dc:date xsi:type="dcterms:W3CDTF">2012-01-01</dc:date>
|
14
|
+
<dc:description><%= @metadata['description'] %></dc:description>
|
15
|
+
<dc:rights><%= @metadata['copyright'] %></dc:rights>
|
16
|
+
</metadata>
|
17
|
+
|
18
|
+
<manifest>
|
19
|
+
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
|
20
|
+
<item id="css" href="epub.css" media-type="text/css" />
|
21
|
+
<%= manifest_items %>
|
22
|
+
</manifest>
|
23
|
+
|
24
|
+
<spine toc="ncx">
|
25
|
+
<%= spine_items %>
|
26
|
+
</spine>
|
27
|
+
|
28
|
+
<guide>
|
29
|
+
<reference type="toc" title="Table of Contents" href="toc.html" />
|
30
|
+
<reference type="text" title="Text" href="covertext.html" />
|
31
|
+
</guide>
|
32
|
+
|
33
|
+
</package>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
<meta name="language" content="de">
|
6
|
+
<link rel="stylesheet" type="text/css" href="epub.css" media="screen">
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<%= @body %>
|
10
|
+
</body>
|
11
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<item href="<%= filename %>" id="<%= id %>" media-type="<%= mediatype %>"/>
|
@@ -0,0 +1 @@
|
|
1
|
+
<itemref idref="<%= id %>" />
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
|
3
|
+
|
4
|
+
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
5
|
+
|
6
|
+
<head>
|
7
|
+
<meta name="dtb:uid" content="http://www.hxa7241.org/articles/content/epup-guide_hxa7241_2007_2.epub"/>
|
8
|
+
<meta name="dtb:depth" content="2"/>
|
9
|
+
<meta name="dtb:totalPageCount" content="0"/>
|
10
|
+
<meta name="dtb:maxPageNumber" content="0"/>
|
11
|
+
</head>
|
12
|
+
|
13
|
+
<docTitle>
|
14
|
+
<text><%= @name %></text>
|
15
|
+
</docTitle>
|
16
|
+
|
17
|
+
<navMap>
|
18
|
+
<%= nav_points %>
|
19
|
+
</navMap>
|
20
|
+
|
21
|
+
</ncx>
|
data/lib/publishr.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# PublishR -- Fast publishing for ebooks and paper
|
2
|
+
# Copyright (C) 2012 Michael Franzl
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
require 'kramdown'
|
19
|
+
require 'erb'
|
20
|
+
require 'yaml'
|
21
|
+
require 'fileutils'
|
22
|
+
|
23
|
+
require 'publishr/project'
|
24
|
+
require 'publishr/markup_processor'
|
25
|
+
require 'publishr/epub_renderer'
|
26
|
+
require 'publishr/latex_processor'
|
27
|
+
require 'publishr/latex_renderer'
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# PublishR -- Fast publishing for ebooks and paper
|
2
|
+
# Copyright (C) 2012 Michael Franzl
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
module Publishr
|
19
|
+
class EpubRenderer
|
20
|
+
def initialize(name,inpath,outpath,metadata)
|
21
|
+
@name = name
|
22
|
+
@inpath = inpath
|
23
|
+
@outpath = outpath
|
24
|
+
@metadata = metadata
|
25
|
+
@gempath = File.expand_path('../../../', __FILE__)
|
26
|
+
|
27
|
+
@html_files = []
|
28
|
+
@image_files = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def render
|
32
|
+
make_epub_directory_structure
|
33
|
+
render_htmls
|
34
|
+
compile_xmls
|
35
|
+
end
|
36
|
+
|
37
|
+
def make_epub_directory_structure
|
38
|
+
FileUtils.rm_rf @outpath
|
39
|
+
FileUtils.cp_r File.join(@gempath,'lib','epub_skeleton'), @outpath
|
40
|
+
FileUtils.cp Dir[File.join(@inpath,'..','images','*.jpg')], @outpath
|
41
|
+
FileUtils.cp Dir[File.join(@inpath,'images','*.jpg')], @outpath
|
42
|
+
FileUtils.cp File.join(@inpath,'cover.jpg'), @outpath
|
43
|
+
@image_files = Dir[File.join(@outpath,'*.jpg')]
|
44
|
+
# users can provide an overriding css file
|
45
|
+
FileUtils.cp_f File.join(@inpath,'epub.css'), @outpath if File.exists?(File.join(@inpath,'epub.css'))
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_htmls
|
49
|
+
kramdown_options = {
|
50
|
+
:auto_ids => false,
|
51
|
+
:smart_quotes => ["sbquo", "lsquo", "bdquo", "ldquo"],
|
52
|
+
:template => File.join(@gempath,'lib','epub_templates','kramdown.html')
|
53
|
+
}
|
54
|
+
Dir[File.join(@inpath,'*.txt')].each do |infilepath|
|
55
|
+
kramdown = File.open(infilepath, 'r').read
|
56
|
+
html = Kramdown::Document.new(kramdown, kramdown_options).to_html
|
57
|
+
degraded_html = MarkupProcessor.new(html,@metadata).degrade
|
58
|
+
outfilepath = File.join(@outpath, File.basename(infilepath).gsub(/(.*).txt/, '\1.html'))
|
59
|
+
File.open(outfilepath, 'w'){ |f| f.write degraded_html }
|
60
|
+
end
|
61
|
+
@html_files = ([File.join(@outpath,'covertext.html')] + [File.join(@outpath,'frontmatter.html')] + [File.join(@outpath,'toc.html')] + Dir[File.join(@outpath,'*.html')].sort).uniq
|
62
|
+
end
|
63
|
+
|
64
|
+
def compile_xmls
|
65
|
+
File.open(File.join(@outpath,'content.opf'),'w'){ |f| f.write render_content_opf }
|
66
|
+
File.open(File.join(@outpath,'toc.ncx'),'w'){ |f| f.write render_toc_ncx }
|
67
|
+
Dir.chdir @outpath
|
68
|
+
filename = File.join(@inpath,"#{ @name }.epub")
|
69
|
+
`zip -X0 #{ filename } mimetype`
|
70
|
+
`zip -Xur9D #{ filename } *`
|
71
|
+
end
|
72
|
+
|
73
|
+
def render_content_opf
|
74
|
+
erb = File.open(File.join(@gempath,'lib','epub_templates','content.opf.erb'),'r').read
|
75
|
+
spine_items = render_spine_items
|
76
|
+
manifest_items = render_manifest_items
|
77
|
+
ERB.new(erb).result binding
|
78
|
+
end
|
79
|
+
|
80
|
+
def render_toc_ncx
|
81
|
+
erb = File.open(File.join(@gempath,'lib','epub_templates','toc.ncx.erb'),'r').read
|
82
|
+
nav_points = render_nav_points
|
83
|
+
ERB.new(erb).result binding
|
84
|
+
end
|
85
|
+
|
86
|
+
def render_nav_points
|
87
|
+
erb = File.open(File.join(@gempath,'lib','epub_templates','nav_points.erb'),'r').read
|
88
|
+
results = []
|
89
|
+
i = 0
|
90
|
+
@html_files.each do |h|
|
91
|
+
filename = File.basename(h)
|
92
|
+
id = filename.gsub '.',''
|
93
|
+
i += 1
|
94
|
+
results << (ERB.new(erb).result binding)
|
95
|
+
end
|
96
|
+
results.join("\n")
|
97
|
+
end
|
98
|
+
|
99
|
+
def render_manifest_items
|
100
|
+
image_files = Dir[File.join(@outpath,'*.jpg')]
|
101
|
+
erb = File.open(File.join(@gempath,'lib','epub_templates','manifest_items.erb'),'r').read
|
102
|
+
results = []
|
103
|
+
(@html_files + @image_files).each do |h|
|
104
|
+
filename = File.basename(h)
|
105
|
+
id = filename.gsub '.',''
|
106
|
+
mediatype = case File.extname(h)
|
107
|
+
when '.html' then 'application/xhtml+xml'
|
108
|
+
when '.jpg' then 'image/jpeg'
|
109
|
+
when '.png' then 'image/png'
|
110
|
+
end
|
111
|
+
results << (ERB.new(erb).result binding)
|
112
|
+
end
|
113
|
+
results.join("\n")
|
114
|
+
end
|
115
|
+
|
116
|
+
def render_spine_items
|
117
|
+
erb = File.open(File.join(@gempath,'lib','epub_templates','spine_items.erb'),'r').read
|
118
|
+
results = []
|
119
|
+
@html_files.each do |h|
|
120
|
+
id = File.basename(h).gsub '.',''
|
121
|
+
results << (ERB.new(erb).result binding)
|
122
|
+
end
|
123
|
+
results.join("\n")
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Encoding: UTF-8
|
2
|
+
|
3
|
+
# PublishR -- Fast publishing for ebooks and paper
|
4
|
+
# Copyright (C) 2012 Michael Franzl
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as
|
8
|
+
# published by the Free Software Foundation, either version 3 of the
|
9
|
+
# License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module Publishr
|
21
|
+
class LatexProcessor
|
22
|
+
def initialize(latex,inpath)
|
23
|
+
@lines = latex.split("\n")
|
24
|
+
@line = ''
|
25
|
+
@inpath = inpath
|
26
|
+
|
27
|
+
@custom_fixes = File.open(File.join(@inpath,'latex_postprocessing.rb'), 'r').read if File.exists?(File.join(@inpath,'latex_postprocessing.rb', 'r'))
|
28
|
+
@global_fixes = File.open(File.join(@inpath,'..','latex_postprocessing.rb'), 'r').read if File.exists?(File.join(@inpath,'..','latex_postprocessing.rb'))
|
29
|
+
end
|
30
|
+
|
31
|
+
def fix
|
32
|
+
processed_lines = []
|
33
|
+
@lines.each do |l|
|
34
|
+
@line = l
|
35
|
+
process_line
|
36
|
+
processed_lines << @line
|
37
|
+
end
|
38
|
+
processed_lines.join("\n")
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_line
|
42
|
+
@line.gsub! /.hypertarget{.*?}{}/, ''
|
43
|
+
@line.gsub! /.label{.*?}/, ''
|
44
|
+
|
45
|
+
# latex uses eps, so remove jpg ending
|
46
|
+
@line.gsub! /(.includegraphics{.*?).jpg}/, '\1}'
|
47
|
+
|
48
|
+
# better formatting for names, book titles and technical terms
|
49
|
+
@line.gsub! /name\((.*?)\)/, '\name{\1}'
|
50
|
+
@line.gsub! /title\((.*?)\)/, '\book{\1}'
|
51
|
+
@line.gsub! /{\\tt (.*?)}/, '\object{\1}'
|
52
|
+
|
53
|
+
# covert kramdown css attributes to LaTeX environments
|
54
|
+
@line.gsub! /{quot(.*?)} % class="(.*?)"/, '{quot\1\2}'
|
55
|
+
@line.gsub! /{quote}/, '{quotenormal}'
|
56
|
+
@line.gsub! /{quotation}/, '{quotationnormal}'
|
57
|
+
|
58
|
+
# transform custom kramdown comments
|
59
|
+
@line.gsub! '% bigskip', "\\bigskip"
|
60
|
+
@line.gsub! '% pagebreak', "\\pagebreak[4]"
|
61
|
+
@line.gsub! '% newpage', "\\newpage"
|
62
|
+
|
63
|
+
# bind ellipsis to previous word
|
64
|
+
@line.gsub! /(\w \\ldots{})/, '\\mbox{\1}'
|
65
|
+
|
66
|
+
# set better space for [...]
|
67
|
+
@line.gsub! /\[\\ldots{}\]/, '\\omission{}'
|
68
|
+
|
69
|
+
# separate thousands, beginning with 10000
|
70
|
+
@line.gsub! /(\d\d)(\d\d\d) /, '\1\\,\2 '
|
71
|
+
|
72
|
+
@line.gsub! '°', '\\textdegree'
|
73
|
+
|
74
|
+
eval(@custom_fixes, binding) if @custom_fixes
|
75
|
+
eval(@global_fixes, binding) if @global_fixes
|
76
|
+
|
77
|
+
# use correct hyphen code for better automatic hyphenation
|
78
|
+
@line.gsub! /(\w)-(\w)/, '\1\\hyp{}\2'
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# PublishR -- Fast publishing for ebooks and paper
|
2
|
+
# Copyright (C) 2012 Michael Franzl
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
module Publishr
|
19
|
+
class LatexRenderer
|
20
|
+
def initialize(name,path)
|
21
|
+
@name = name
|
22
|
+
@inpath = path
|
23
|
+
@outpath = File.join(@inpath,'latex')
|
24
|
+
@gempath = File.expand_path('../../../', __FILE__)
|
25
|
+
end
|
26
|
+
|
27
|
+
def render
|
28
|
+
make_tex_directory_structure
|
29
|
+
render_tex
|
30
|
+
end
|
31
|
+
|
32
|
+
def make_tex_directory_structure
|
33
|
+
FileUtils.mkdir_p @outpath
|
34
|
+
FileUtils.cp Dir[File.join(@inpath,'..','images','*.jpg')], @outpath
|
35
|
+
FileUtils.cp Dir[File.join(@inpath,'images','*.jpg')], @outpath
|
36
|
+
FileUtils.cp_r File.join(@gempath,'lib','tex_templates','book.tex'), @outpath
|
37
|
+
FileUtils.cp_r File.join(@inpath,'preamble.tex'), @outpath
|
38
|
+
end
|
39
|
+
|
40
|
+
def render_tex
|
41
|
+
kramdown_options = {
|
42
|
+
:latex_headers => ['chapter*', "section*", "subsection*", "subsubsection*", "paragraph*", "subparagraph*"],
|
43
|
+
:smart_quotes => ["sbquo", "lsquo", "bdquo", "ldquo"]
|
44
|
+
}
|
45
|
+
Dir[File.join(@inpath,'*.txt')].each do |infilepath|
|
46
|
+
kramdown = File.open(infilepath, 'r').read
|
47
|
+
latex = Kramdown::Document.new(kramdown, kramdown_options).to_latex
|
48
|
+
fixed_latex = LatexProcessor.new(latex,@inpath).fix
|
49
|
+
outfilepath = File.join(@outpath, File.basename(infilepath).gsub(/(.*).txt/, '\1.tex'))
|
50
|
+
File.open(outfilepath, 'w'){ |f| f.write fixed_latex }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Publishr
|
3
|
+
class MarkupProcessor
|
4
|
+
def initialize(markup,metadata)
|
5
|
+
@lines = markup.split("\n")
|
6
|
+
@line = ''
|
7
|
+
@metadata = metadata
|
8
|
+
|
9
|
+
@depth = 0
|
10
|
+
@quotetype = nil
|
11
|
+
@add_footnote = false
|
12
|
+
@process_footnotes = false
|
13
|
+
@footnote_number = 0
|
14
|
+
@footnote_reference = ''
|
15
|
+
end
|
16
|
+
|
17
|
+
def degrade
|
18
|
+
processed_lines = []
|
19
|
+
@lines.each do |l|
|
20
|
+
@line = l
|
21
|
+
process_line
|
22
|
+
processed_lines << @line
|
23
|
+
end
|
24
|
+
processed_lines.join("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_line
|
28
|
+
@process_footnotes = true if @line.include?('<div class="footnotes">')
|
29
|
+
@process_footnotes = false if @process_footnotes == true and @line.include?('</div>')
|
30
|
+
@add_footnote = true and @footnote_number += 1 if @line.include?('<li id="fn')
|
31
|
+
|
32
|
+
annotate_blockquote
|
33
|
+
improve_typography
|
34
|
+
make_uppercase
|
35
|
+
change_footnote_references
|
36
|
+
process_footnotes if @process_footnotes == true
|
37
|
+
add_footnote if @add_footnote == true and @line.include?('<p>')
|
38
|
+
end
|
39
|
+
|
40
|
+
def improve_typography
|
41
|
+
@line.gsub! '<em>', '<b>'
|
42
|
+
@line.gsub! '</em>', '</b>'
|
43
|
+
@line.gsub!(/title\((.*?)\)/,'<cite>\1</cite>')
|
44
|
+
@line.gsub!(/name\((.*?)\)/,'<var>\1</var>')
|
45
|
+
@line.gsub!(/(\(\w\))/,'<i>\1</i>')
|
46
|
+
|
47
|
+
if @language == 'de'
|
48
|
+
@line.gsub!(/([FA]:)/,'<b>\1</b>')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Kindle doesn't recognize <blockquote>, so add class to p tags depending on the blockquote depth
|
54
|
+
def annotate_blockquote
|
55
|
+
if @line.include?('<blockquote')
|
56
|
+
@depth += 1
|
57
|
+
@quotetype = /<blockquote class="(.*?)">/.match(@line) if @depth == 1
|
58
|
+
end
|
59
|
+
if @line.include?('</blockquote')
|
60
|
+
@depth -= 1
|
61
|
+
@quotetype = nil if @depth.zero?
|
62
|
+
end
|
63
|
+
@line.gsub!(/<p/,"<p class=\"blockquote_#{ @quotetype[1] if @quotetype }_#{ @depth }\"") unless @depth.zero?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Kindle doesn't recognize text-transform: uppercase;
|
67
|
+
def make_uppercase
|
68
|
+
@line.gsub!(/<var>(.*?)<\/var>/){ "<cite>#{ $1.upcase }</cite>" }
|
69
|
+
@line.gsub!(/<h1(.*?)>(.*?)<\/h1>/){ "<h1#{ $1 }>#{ $2.upcase }</h1><hr />" }
|
70
|
+
end
|
71
|
+
|
72
|
+
def change_footnote_references
|
73
|
+
@line.gsub! /<sup id="fnref:.*?">/, ''
|
74
|
+
@line.gsub! '</sup>', ''
|
75
|
+
@line.gsub! /rel="footnote">(.*?)<\/a>/, '> [\1]</a>'
|
76
|
+
@line.gsub!(/(<div class=.footnotes.>)/){ "<br style='page-break-before:always;'>#{ $1 }<h4>#{ @metadata['footnote_heading'] }</h4>" }
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_footnotes
|
80
|
+
@line.gsub!(/<p(.*?)>/){ "<p>" }
|
81
|
+
@footnote_reference = /<li (id="fn.*")/.match(@line)[1] if @line.include?('<li id="fn')
|
82
|
+
@line.gsub! /<li id="fn.*>/, ''
|
83
|
+
@line.gsub! /<\/li>/, ''
|
84
|
+
@line.gsub! /<ol>/, ''
|
85
|
+
@line.gsub! /<\/ol>/, ''
|
86
|
+
@line.gsub! /<a href="#fnref.*<\/a>/, ''
|
87
|
+
end
|
88
|
+
|
89
|
+
# Kindle doesn't display <ol> list numbers when jumping to a footnote, so replace them with conventional text
|
90
|
+
def add_footnote
|
91
|
+
@line.gsub! /<p>/, "<hr><p class='footnote' #{ @footnote_reference }><b>[#{ @footnote_number }]</b>: "
|
92
|
+
@add_footnote = false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# PublishR -- Fast publishing for ebooks and paper
|
2
|
+
# Copyright (C) 2012 Michael Franzl
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
module Publishr
|
19
|
+
class Project
|
20
|
+
def initialize(name,relativepath,converterspath)
|
21
|
+
@name = name
|
22
|
+
@inpath = File.join(Dir.pwd,relativepath)
|
23
|
+
@converterspath = File.join(Dir.pwd,converterspath)
|
24
|
+
|
25
|
+
@metadata = YAML::load(File.open(File.join(@inpath,'metadata.yml'), 'r').read)
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_kindle
|
29
|
+
outpath = File.join(@inpath,'epub')
|
30
|
+
epub = EpubRenderer.new(@name,@inpath,outpath,@metadata)
|
31
|
+
epub.render
|
32
|
+
binaryfile = File.join(@converterspath,'kindlegen')
|
33
|
+
epubfile = File.join(@inpath,"#{ @name }.epub")
|
34
|
+
IO.popen("#{ binaryfile } -verbose #{ epubfile }") do |io|
|
35
|
+
while (line = io.gets) do
|
36
|
+
puts line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
FileUtils.rm_r outpath
|
40
|
+
FileUtils.cp File.join(@inpath,"#{ @name }.mobi"), '/media/Kindle/documents'
|
41
|
+
end
|
42
|
+
|
43
|
+
def make_pdf
|
44
|
+
pdf = LatexRenderer.new(@name,@inpath)
|
45
|
+
pdf.render
|
46
|
+
|
47
|
+
outpath = File.join(@inpath,'latex')
|
48
|
+
binaryfile = File.join(@converterspath,'jpeg2ps')
|
49
|
+
Dir[File.join(outpath,'*.jpg')].each do |infilepath|
|
50
|
+
outfilepath = File.join(outpath, File.basename(infilepath).gsub(/(.*).jpg/, '\1.eps'))
|
51
|
+
`#{ binaryfile } -r 0 -o #{ outfilepath } #{ infilepath }`
|
52
|
+
end
|
53
|
+
|
54
|
+
Dir.chdir outpath
|
55
|
+
IO.popen('pdflatex preamble.tex') do |io|
|
56
|
+
while (line = io.gets) do
|
57
|
+
puts line
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
FileUtils.mv File.join(outpath,'preamble.pdf'), File.join(@inpath,"#{ @name }.pdf")
|
62
|
+
#FileUtils.rm_r outpath
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/publishr.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "publishr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "publishr"
|
7
|
+
s.version = Publishr::VERSION
|
8
|
+
s.authors = ["Michael Franzl"]
|
9
|
+
s.email = ["michael@billgastro.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Fast publishing for ebooks and paper}
|
12
|
+
s.description = %q{Fast publishing for ebooks and paper}
|
13
|
+
|
14
|
+
s.rubyforge_project = "publishr"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: publishr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Franzl
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-02 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Fast publishing for ebooks and paper
|
15
|
+
email:
|
16
|
+
- michael@billgastro.com
|
17
|
+
executables:
|
18
|
+
- publishr
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- Rakefile
|
25
|
+
- bin/publishr
|
26
|
+
- lib/epub_skeleton/META-INF/container.xml
|
27
|
+
- lib/epub_skeleton/epub.css
|
28
|
+
- lib/epub_skeleton/mimetype
|
29
|
+
- lib/epub_templates/content.opf.erb
|
30
|
+
- lib/epub_templates/kramdown.html
|
31
|
+
- lib/epub_templates/manifest_items.erb
|
32
|
+
- lib/epub_templates/nav_points.erb
|
33
|
+
- lib/epub_templates/spine_items.erb
|
34
|
+
- lib/epub_templates/toc.ncx.erb
|
35
|
+
- lib/publishr.rb
|
36
|
+
- lib/publishr/epub_renderer.rb
|
37
|
+
- lib/publishr/latex_processor.rb
|
38
|
+
- lib/publishr/latex_renderer.rb
|
39
|
+
- lib/publishr/markup_processor.rb
|
40
|
+
- lib/publishr/project.rb
|
41
|
+
- lib/publishr/version.rb
|
42
|
+
- publishr.gemspec
|
43
|
+
homepage: ''
|
44
|
+
licenses: []
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project: publishr
|
63
|
+
rubygems_version: 1.8.10
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Fast publishing for ebooks and paper
|
67
|
+
test_files: []
|