mirror of
https://github.com/Neetpone/foalfetch.git
synced 2025-02-12 03:16:43 +01:00
feature: initial implementation of EPUB generation
This commit is contained in:
parent
9ced0594e1
commit
3d7f2a51ce
8 changed files with 164 additions and 22 deletions
1
Gemfile
1
Gemfile
|
@ -26,6 +26,7 @@ gem 'puma', '~> 5.0'
|
|||
gem 'sidekiq'
|
||||
|
||||
# Other stuff
|
||||
gem 'gepub'
|
||||
gem 'marcel'
|
||||
|
||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||
|
|
|
@ -120,6 +120,9 @@ GEM
|
|||
faraday-net_http (>= 2.0, < 3.2)
|
||||
faraday-net_http (3.1.0)
|
||||
net-http
|
||||
gepub (1.0.15)
|
||||
nokogiri (>= 1.8.2, < 2.0)
|
||||
rubyzip (> 1.1.1, < 2.4)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
hashie (5.0.0)
|
||||
|
@ -305,6 +308,7 @@ DEPENDENCIES
|
|||
debug
|
||||
elasticsearch-model
|
||||
fancy_searchable!
|
||||
gepub
|
||||
kaminari
|
||||
marcel
|
||||
model-msearch
|
||||
|
|
|
@ -6,27 +6,6 @@ class ChaptersController < ApplicationController
|
|||
@story = Story.find(params[:story_id])
|
||||
@chapter = @story.chapters.find_by(number: params[:id])
|
||||
|
||||
@rendered_html = render_story
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_story
|
||||
body = @chapter.body
|
||||
body.lstrip!
|
||||
body = body.split "\n"
|
||||
|
||||
# This is fucking bad, this gets rid of the redundant title - this should be fixed upstairs,
|
||||
# in the actual generation of the Markdown.
|
||||
if body.length >= 2 && body[0] == @chapter.title && !body[1].empty? && body[1][0] == '='
|
||||
body = body[2..]
|
||||
end
|
||||
|
||||
markdown.render body.join("\n")
|
||||
end
|
||||
|
||||
def markdown
|
||||
@@markdown ||=
|
||||
Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true)
|
||||
@rendered_html = StoryRenderer.render_chapter(@chapter)
|
||||
end
|
||||
end
|
||||
|
|
43
app/lib/ebook/epub_generator.rb
Normal file
43
app/lib/ebook/epub_generator.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
require 'gepub'
|
||||
|
||||
TEMPLATE_DIRECTORY = Rails.root.join('app/lib/ebook')
|
||||
|
||||
class Ebook::EpubGenerator
|
||||
include ActionView::Helpers::TagHelper
|
||||
|
||||
def initialize(story)
|
||||
@story = story
|
||||
end
|
||||
|
||||
def generate
|
||||
book = GEPUB::Book.new
|
||||
book.add_title @story.title, title_type: GEPUB::TITLE_TYPE::MAIN, lang: :en, display_seq: 1
|
||||
book.add_creator @story.author.name
|
||||
book.add_item 'styles.css', content: TEMPLATE_DIRECTORY.join('files/styles.css').open
|
||||
|
||||
book.ordered do
|
||||
book.add_item('CoverPage.html', content: generate_cover_page).landmark(type: 'cover', title: 'Cover Page')
|
||||
@story.chapters.each do |chapter|
|
||||
book.add_item("Chapter#{chapter.number}.html", content: generate_chapter(chapter))
|
||||
.toc_text("Chapter #{chapter.number} - #{chapter.title}")
|
||||
.landmark(type: 'bodymatter', title: chapter.title)
|
||||
end
|
||||
end
|
||||
|
||||
book
|
||||
end
|
||||
|
||||
#private
|
||||
|
||||
def render_template(name, context)
|
||||
Slim::Template.new(TEMPLATE_DIRECTORY.join("templates/#{name}.html.slim")).render(context)
|
||||
end
|
||||
|
||||
def generate_cover_page
|
||||
StringIO.new render_template('cover', @story)
|
||||
end
|
||||
|
||||
def generate_chapter(chapter)
|
||||
StringIO.new render_template('chapter', chapter)
|
||||
end
|
||||
end
|
72
app/lib/ebook/files/styles.css
Normal file
72
app/lib/ebook/files/styles.css
Normal file
|
@ -0,0 +1,72 @@
|
|||
.double {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.indented {
|
||||
text-indent: 3em;
|
||||
}
|
||||
.i {
|
||||
font-style: italic;
|
||||
}
|
||||
.u {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.b {
|
||||
font-weight: bold;
|
||||
}
|
||||
.c {
|
||||
text-align: center;
|
||||
}
|
||||
.s {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
img.emoticon {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
height: 1em;
|
||||
}
|
||||
hr {
|
||||
margin-top: 12px;
|
||||
}
|
||||
blockquote {
|
||||
padding: 5px 10px;
|
||||
margin: 10px;
|
||||
border-left: 5px solid #aaa;
|
||||
background: #eee;
|
||||
}
|
||||
.authors-note,
|
||||
.preface {
|
||||
border-top: 3px double #333;
|
||||
border-bottom: 3px double #333;
|
||||
}
|
||||
.afterward {
|
||||
border-top: 3px double #333;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.9em;
|
||||
margin: 0.8em 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.3em;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: 0.625em;
|
||||
margin: 0;
|
||||
}
|
||||
.authors-note,
|
||||
.preface,
|
||||
.afterward {
|
||||
background: none;
|
||||
border-left: none;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.authors-note h1,
|
||||
.authors-note h2,
|
||||
.preface h1,
|
||||
.preface h2,
|
||||
.afterward h1,
|
||||
.afterward h2 {
|
||||
margin: 0.5em 0;
|
||||
font-size: 1.3em;
|
||||
}
|
10
app/lib/ebook/templates/chapter.html.slim
Normal file
10
app/lib/ebook/templates/chapter.html.slim
Normal file
|
@ -0,0 +1,10 @@
|
|||
doctype xml
|
||||
html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
|
||||
head
|
||||
meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
|
||||
link rel="stylesheet" href="styles.css"
|
||||
title= title
|
||||
body
|
||||
h1= title
|
||||
.calibre2#content
|
||||
== StoryRenderer.render_chapter(self)
|
33
app/lib/ebook/templates/cover.html.slim
Normal file
33
app/lib/ebook/templates/cover.html.slim
Normal file
|
@ -0,0 +1,33 @@
|
|||
doctype xml
|
||||
html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
|
||||
head
|
||||
meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
|
||||
link rel="stylesheet" href="styles.css"
|
||||
title Cover
|
||||
body
|
||||
table style="width: 100%; height: 100%;"
|
||||
tr
|
||||
td
|
||||
h1= title
|
||||
p
|
||||
b by #{author.name}
|
||||
hr
|
||||
p
|
||||
| Rating: #{content_rating}
|
||||
br
|
||||
| Tags: #{tags.pluck(:name).join(', ')}
|
||||
br
|
||||
| Length: #{num_words}
|
||||
hr
|
||||
table.desc
|
||||
tr style="height: 100%;" valign="top"
|
||||
td
|
||||
p.double= short_description
|
||||
== description_html
|
||||
tr.bottom
|
||||
td
|
||||
hr
|
||||
p
|
||||
| Published #{date_published}
|
||||
br
|
||||
| Last updated #{date_updated}
|
BIN
test.epub
Normal file
BIN
test.epub
Normal file
Binary file not shown.
Loading…
Reference in a new issue