diff options
| author | Marat Radchenko <marat@slonopotamus.org> | 2024-01-16 11:12:02 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-16 22:12:02 +0300 |
| commit | 394ec4cd5283725f1e1c92fde8266524b26aebfd (patch) | |
| tree | 6fd7745d1b254a75b3f95fc4691b368a0a77a0ef | |
| parent | aec6be126965f622624f611070645fc1931bf18a (diff) | |
Drop MOBI support (#458)
Amazon is slowly killing it, it's just a question of time when it fully dies.
References:
* https://kdp.amazon.com/en_US/help/topic/GULSQMHU5MNH4EZM
> Starting August 1, 2021, we will no longer support MOBI files for reflowable eBooks. Use EPUB, DOCX or KPF to publish new or update reflowable eBooks.
* https://www.amazon.com/gp/help/customer/display.html?nodeId=G5WYD9SAF7PGXRNA
> Beginning in late 2022, you'll no longer be able to send MOBI (.AZW, .MOBI) files to your Kindle library using Send to Kindle. This change won't affect any MOBI files already in your Kindle library. You can still read them with Kindle. MOBI is an older file format and won't support the newest Kindle features for documents.
* https://www.reddit.com/r/kindle/comments/16rw6e3/amazon_announcement_about_mobi_support_timeline/
> We will end all Send to Kindle support for MOBI files by December 20, 2023.
* https://www.mobileread.com/forums/showthread.php?t=336365
> Does anyone still have Kindle Previewer installer older than 3.49 that you could share? The reason I am looking for it is because newer versions no longer open .mobi files.
| -rw-r--r-- | CHANGELOG.adoc | 4 | ||||
| -rw-r--r-- | Gemfile | 4 | ||||
| -rw-r--r-- | README.adoc | 11 | ||||
| -rw-r--r-- | WORKLOG.adoc | 12 | ||||
| -rw-r--r-- | asciidoctor-epub3.gemspec | 6 | ||||
| -rwxr-xr-x | bin/adb-push-ebook | 37 | ||||
| -rw-r--r-- | data/samples/sample-book.adoc | 2 | ||||
| -rw-r--r-- | data/styles/epub3-css3-only.scss | 1 | ||||
| -rw-r--r-- | data/styles/epub3.scss | 7 | ||||
| -rw-r--r-- | docs/modules/ROOT/pages/index.adoc | 176 | ||||
| -rw-r--r-- | lib/asciidoctor-epub3/converter.rb | 198 | ||||
| -rw-r--r-- | spec/cli_spec.rb | 22 | ||||
| -rw-r--r-- | spec/converter_spec.rb | 4 | ||||
| -rw-r--r-- | spec/spec_helper.rb | 15 |
14 files changed, 59 insertions, 440 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index ccebb08..3d74bdd 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,6 +5,10 @@ This document provides a high-level view of the changes to the {project-name} by release. For a detailed view of what has changed, refer to the {uri-repo}/commits/master[commit history] on GitHub. +== Unreleased + +* Drop MOBI support + == 2.0.1 (2024-01-13) - @slonopotamus * restore styling of `<strong>` and `<em>` (#461) @@ -9,8 +9,4 @@ group :optional do # epubcheck-ruby might be safe to be converted into runtime dependency, # but could have issues when packaged into asciidoctorj-epub3 gem 'epubcheck-ruby', '~> 5.1.0.0' - - # Kindlegen is unavailable neither for 64-bit x86 macOS nor for ARM - # Also, skip JRuby on Windows for now. See https://github.com/jruby/jruby/issues/7171 - gem 'kindlegen', '~> 3.1.0' unless RUBY_PLATFORM =~ /darwin/ || (Gem.win_platform? && RUBY_ENGINE == 'jruby') end diff --git a/README.adoc b/README.adoc index 833e138..67a6d13 100644 --- a/README.adoc +++ b/README.adoc @@ -12,7 +12,7 @@ image:https://img.shields.io/badge/zulip-join_chat-brightgreen.svg[project chat, image:https://img.shields.io/gem/v/asciidoctor-epub3.svg[Latest Release,link={uri-gem}] image:{uri-project}/workflows/CI/badge.svg?branch=main[GitHub Actions,link={uri-ci}] -{project-name} is a set of Asciidoctor extensions for converting AsciiDoc documents directly to the EPUB3 and KF8/MOBI e-book formats. +{project-name} is a set of Asciidoctor extensions for converting AsciiDoc documents directly to the EPUB3 e-book format. == Documentation @@ -53,15 +53,6 @@ $ asciidoctor-epub3 -D output path/to/book.adoc When the script completes, you'll see the file [file]_book.epub_ appear in the [path]_output_ directory. Open that file with an EPUB3 reader to view the result. -You may also produce KF8/MOBI file by setting `ebook-format` attribute to `kf8`. - -[source,shell script] ----- -$ asciidoctor-epub3 -D output -a ebook-format=kf8 path/to/book.adoc ----- - -When the script completes, the file [file]_book.mobi_ will appear in [path]_output_ directory. - == Contributing In the spirit of free software, _everyone_ is encouraged to help improve this project. diff --git a/WORKLOG.adoc b/WORKLOG.adoc index 237cf68..00bb57e 100644 --- a/WORKLOG.adoc +++ b/WORKLOG.adoc @@ -14,8 +14,6 @@ * reorder sections in README; needs to flow a bit better...Getting Started is too large & after Structuring your Manuscript * link to https://medium.com/@sandersk/responsive-ebook-design-a-primer-8bba01328219 in style section in README * only uppercase document title if detected in CSS -* add empty front matter page in kf8 version if one is specified to allow navigation to first entry from TOC - ** why can't we navigate to first chapter on Kindle from TOC? * document more clearly how to provide your own CSS ** currently it's not possible to override the epub3-fonts.css (though it should be) * cleanup this sanitize XML stuff; move to Asciidoctor::Helpers? @@ -43,7 +41,6 @@ * MEDIUM: add icon & icon placement as attributes on btn macro * MEDIUM: move client sniffer JavaScript to file and read/include from converter * MEDIUM: use the dfn element for defining a definition of a term (not just term class); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn -* MEDIUM: to remove text indent in mobi7, set width="0pt" (text-indent) on <p> tag; also set height="1em" (margin top) * MEDIUM: create back link in bibliography entry for each reference to it (currently only the first) * implement checklists @@ -70,14 +67,12 @@ table.table div.embed > *:not(p) { font-size: 1.25em; } -* HIGH: kindlegen no longer strips <header> elements, so we can drop our div wrapper hack * HIGH: don't set text color so light on monochrome devices (use media query to detect) (#67) * HIGH: make justify-text a class on body that can be controlled from AsciiDoc attribute * HIGH: image border option (or add drop shadow to screenshots in README) * HIGH: review the table border color * HIGH: style example block * HIGH: allow theme to be customized using stylesheet attribute -* HIGH: move -webkit-hyphens: auto to epub3-css3-only inside @media not amzn-kf8? (if we decide to reenable) * MEDIUM: headshot has too much top margin when at top of page (not below section title) * MEDIUM: namo pubtree is justifying preformatted blocks (still true?) * support both jpg and png avatars @@ -131,13 +126,6 @@ * Control+Shift+u to type in a unicode sequent, then press enter to accept * Calibre gets confused when there are local fonts that closely match font in stylesheet, uses them over embedded styles (in particular M+ weights) * iBooks info: http://authoradventures.blogspot.com/2013/08/ibooks-tutorial-update-version-30.html -* use the following media query to target non-Kindle devices (works in iBooks at least) - - @media not amzn-kf8 { - @media not amzn-mobi { - } - } - * selector for all prose text (including symbols) body p, ul, ol, li, dl, dt, dd, figcaption, caption, footer, diff --git a/asciidoctor-epub3.gemspec b/asciidoctor-epub3.gemspec index 9741fc6..15f6290 100644 --- a/asciidoctor-epub3.gemspec +++ b/asciidoctor-epub3.gemspec @@ -7,9 +7,9 @@ Gem::Specification.new do |s| s.name = 'asciidoctor-epub3' s.version = Asciidoctor::Epub3::VERSION - s.summary = 'Converts AsciiDoc documents to EPUB3 and KF8/MOBI (Kindle) e-book formats' + s.summary = 'Converts AsciiDoc documents to EPUB3 e-book format' s.description = <<~EOS - An extension for Asciidoctor that converts AsciiDoc documents to EPUB3 and KF8/MOBI (Kindle) e-book archives. + An extension for Asciidoctor that converts AsciiDoc documents to EPUB3 e-book format. EOS s.authors = ['Dan Allen', 'Sarah White'] @@ -25,7 +25,7 @@ Gem::Specification.new do |s| Dir['**/*'] end s.files = files.grep %r{^(?:(?:data/(?:fonts|images|styles)|lib)/.+|Gemfile|Rakefile|LICENSE|(?:CHANGELOG|NOTICE|README)\.adoc|\.yardopts|#{s.name}\.gemspec)$} - s.executables = %w[asciidoctor-epub3 adb-push-ebook] + s.executables = %w[asciidoctor-epub3] s.require_paths = ['lib'] diff --git a/bin/adb-push-ebook b/bin/adb-push-ebook deleted file mode 100755 index ca9b074..0000000 --- a/bin/adb-push-ebook +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -ADB = ENV['ADB'] || 'adb' -TARGETS = { - '.epub' => '/sdcard/', - '.mobi' => '/sdcard/Android/data/com.amazon.kindle/files/' -}.freeze - -unless File.executable? ADB - warn %(adb-push-ebook: `adb` not found.\nPlease set the ADB environment variable or add `adb` to your PATH.) - exit 1 -end - -require 'open3' -require 'shellwords' - -payload_file = ARGV[0] || '_output/sample-book' - -transfers = if (payload_file_ext = File.extname payload_file).empty? - TARGETS.map do |(ext, target_dir)| - { - src: %(#{payload_file}#{ext}), - dest: target_dir - } - end - else - [{ src: payload_file, dest: TARGETS[payload_file_ext] }] - end - -transfers.each do |transfer| - next unless File.file? transfer[:src] - - Open3.popen2e Shellwords.join([ADB, 'push', transfer[:src], transfer[:dest]]) do |_input, output, _wait_thr| - output.each { |line| puts line } - end -end diff --git a/data/samples/sample-book.adoc b/data/samples/sample-book.adoc index 0703e5f..2577c43 100644 --- a/data/samples/sample-book.adoc +++ b/data/samples/sample-book.adoc @@ -6,7 +6,7 @@ v1.0, 2014-04-15 :doctype: book :epub-chapter-level: 2 :producer: Asciidoctor -:keywords: Asciidoctor, samples, e-book, EPUB3, KF8, MOBI, Asciidoctor.js +:keywords: Asciidoctor, samples, e-book, EPUB3, Asciidoctor.js :copyright: CC-BY-SA 3.0 :username: graphitefriction :description: This guide describes the Asciidoctor attributes, values, and layout options available for producing a customized and polished document. diff --git a/data/styles/epub3-css3-only.scss b/data/styles/epub3-css3-only.scss index cd2d600..7f28258 100644 --- a/data/styles/epub3-css3-only.scss +++ b/data/styles/epub3-css3-only.scss @@ -32,6 +32,7 @@ body code, body kbd, body :not(.verse) > pre, :not(.verse) > pre :not(code) { font-family: "M+ 1mn", monospace !important; } +/* TODO: DO we still need this? */ @media amzn-kf8 { /* Kindle does its own margin management, so don't use an explicit margin */ /*body { diff --git a/data/styles/epub3.scss b/data/styles/epub3.scss index be1d5c6..88540c3 100644 --- a/data/styles/epub3.scss +++ b/data/styles/epub3.scss @@ -841,7 +841,7 @@ div.verse { page-break-inside: avoid; } -/* TODO we may want to reenable hyphens here, but not for kf8 */ +/* TODO we may want to reenable hyphens here */ div.verse > pre { font-family: "M+ 1p", sans-serif; background-color: transparent; @@ -1160,7 +1160,10 @@ nav[hidden~="hidden"] { } @media amzn-mobi { - /* NOTE mobi7 doesn't support custom fonts, so revert to generic ones */ + /* + NOTE mobi7 doesn't support custom fonts, so revert to generic ones. + See https://github.com/asciidoctor/asciidoctor-epub3/issues/56. + */ body p, ul, ol, li, dl, dt, dd, figcaption, caption, footer, table.table th, table.table td, div.verse .attribution { font-family: serif; diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 90a84a8..66d658d 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -10,9 +10,6 @@ Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://g :uri-idpf: http://www.idpf.org/ :uri-epub: http://www.idpf.org/epub/31/spec/epub-spec.html :uri-epubcheck: https://github.com/w3c/epubcheck -:uri-kindlegen: https://www.amazon.com/gp/feature.html?docId=1000765211 -:uri-kf8: http://www.amazon.com/gp/feature.html?docId=1000729511 -:uri-send-to-kindle: https://www.amazon.com/gp/sendtokindle/ :uri-metadata-elem: http://www.idpf.org/epub/30/spec/epub30-publications.html#sec-metadata-elem :uri-dc: https://www.dublincore.org/specifications/dublin-core/dces/2004-12-20/ :uri-github-guides: https://guides.github.com @@ -21,11 +18,11 @@ Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://g :uri-epubreadingsystem: http://www.idpf.org/epub/301/spec/epub-contentdocs.html#app-epubReadingSystem :uri-android-sdk: https://developer.android.com/sdk/index.html -{project-name} is a set of Asciidoctor extensions for converting AsciiDoc documents directly to the EPUB3 and KF8/MOBI e-book formats. +{project-name} is a set of Asciidoctor extensions for converting AsciiDoc documents directly to the EPUB3 e-book format. == Introduction -{project-name} is not merely a converter from AsciiDoc to EPUB3 and KF8/MOBI. +{project-name} is not merely a converter from AsciiDoc to EPUB3. Rather, it's a tool for creating highly aesthetic, professional, _easy-to-read_ e-books. Let's face it, many of the technical e-books out there--especially those produced from software documentation--are *_hideous_*. {project-name} is on a mission to disrupt the status quo. @@ -59,10 +56,12 @@ Polish, Polish, and More Polish:: We believe that the e-books produced by {project-name} are the _very best_ output you can expect to find in digital publishing today. Of course, there's always room for improvement, so we'll continue to work with you to achieve and maintain this goal. +{project-name} only produces variable layout (i.e., reflowable) EPUB3 documents since this layout is best suited for the types of documents typically written in AsciiDoc. +We may explore the use of fixed layout documents in the future if the need arises. + === Notable Features * Direct AsciiDoc to EPUB3 conversion -* Direct AsciiDoc to KF8/MOBI conversion * Highly-aesthetic and readable styles with optimized text legibility * Respects font settings (if supported by the e-reader) without altering headings, code or icons * EPUB3 metadata, manifest and spine (assembled by Gepub) @@ -76,23 +75,6 @@ Of course, there's always room for improvement, so we'll continue to work with y * Support for SVG images in the content * Stem blocks via AsciiMath -=== Project Status - -CAUTION: {project-name} is currently _alpha_ software. -Use accordingly. -Although the bulk of AsciiDoc content is converted, there's still work needed to fill in gaps where conversion is incomplete or unstyled. - -NOTE: {project-name} only produces variable layout (i.e., reflowable) EPUB3 documents since this layout is best suited for the types of documents typically written in AsciiDoc. -We may explore the use of fixed layout documents in the future if the need arises. - -== Converter Workflow - -{project-name} takes an aggregate AsciiDoc document and any assets it references as input and produces an EPUB3 publication archive (often described as a “website in a box”). - -{project-name} can also produce KF8/MOBI files, the format required for viewing on Amazon Kindle. -The conversion to KF8/MOBI is performed by generating a slightly modified EPUB3 publication, then passing it through the {uri-kindlegen}[KindleGen] application. -The EPUB3 publication, which can be thought of as the “digital master”, is altered to adhere to certain Amazon Kindle requirements. - == Structuring your Manuscript An EPUB3 archive is composed of multiple files. The content of each “chapter” is typically stored in a dedicated XHTML file. @@ -289,20 +271,11 @@ Suggested values include: book (default), article. |Sets the depth of table of contents metadata. If not set, defaults to `:toclevels:` |=== -When using the EPUB3 converter, the `ebook-format` attribute resolves to the name of the e-book format being generated (epub3 or kf8) and the corresponding attribute `ebook-format-<name>` is defined, where `<name>` is `epub3` or `kf8`. -You can use these attributes in a preprocessor directive if you only want to show certain content to readers using a particular device. -For instance, if you want to display a message to readers on Kindle, you can use: - -[source,asciidoc] ----- -\ifdef::ebook-format-kf8[Hello Kindle reader!] ----- - With that out of the way, it's time to convert the AsciiDoc document directly to EPUB3. == Performing the Conversion -You can convert AsciiDoc documents to EPUB3 and KF8/MOBI from the command line using the `asciidoctor-epub3` script provided with the {project-name} project. +You can convert AsciiDoc documents to EPUB3 from the command line using the `asciidoctor-epub3` script provided with the {project-name} project. === Convert AsciiDoc to EPUB3 @@ -379,27 +352,6 @@ The EPUB3 file will be extracted to a directory adjacent to the generated file, In this example, the contents of the EPUB3 will be extracted to the [path]_output/sample-book_ directory. -=== Convert AsciiDoc to KF8/MOBI - -Creating a KF8/MOBI archive directly from an AsciiDoc document is done with the same generation script (`asciidoctor-epub3`). -You just need to specify the format (`-a ebook-format`) as `kf8`. - - $ asciidoctor-epub3 -D output -a ebook-format=kf8 data/samples/sample-book.adoc - -When the script completes, you'll see the file [file]_sample-book.mobi_ as well as [file]_sample-book-kf8.epub_ (the precursor) appear in the [path]_output_ directory. - -KindleGen does mandatory validation, so you don't need to run the `validate` command after converting to KF8/MOBI. - -.What is KF8? -**** -Kindle Format 8 (KF8) is Amazon's next generation file format offering a wide range of new features and enhancements--including HTML5 and CSS3 support--that publishers can use to create a broad range of books. -The format is close enough to EPUB3 that it's safe to think of it simply as an EPUB3 implementation under most circumstances. -You can read more about the format on the {uri-kf8}[Kindle Format 8 page]. - -Amazon continues to use the _.mobi_ file extension for KF8 archives, despite the fact that they've switched from the Mobipocket format to the EPUB3-like KF8 format. -That's why we refer to the format in this project as KF8/MOBI. -**** - === Tuning Listing Captions Unlike the built-in converters, the EPUB3 converter is configured to add a signifier (e.g., `Listing`) at the start of the caption for all listing and source blocks that have a title. @@ -427,19 +379,9 @@ For more information about this attribute and other related attributes, see {uri *-a ebook-extract* :: Extracts the EPUB3 to a folder in the destination directory after the file is generated -*-a ebook-format=<format>* :: - Specifies the ebook format to generate (epub3 or kf8, default: epub3) - -*-a ebook-kindlegen-path=<path>*:: - Specifies path to KindleGen executable to use when producing KF8/Mobi. - This attribute takes precedence over `KINDLEGEN` environment variable. - *-a ebook-validate* :: Runs {uri-epubcheck}[EPUBCheck] to validate output file against the EPUB3 specification -*-a ebook-compress=<0|1|2|none|standard|huffdic>* :: - Controls the compression type used by kindlegen (0=none [default if unset], 1=standard [default if empty], 2=huffdic) - *-v, --version* :: Display the program version @@ -449,10 +391,6 @@ For more information about this attribute and other related attributes, see {uri Specifies path to EPUBCheck executable to use with `-a ebook-validate`. Effect of this variable can be overriden with `-a ebook-epubcheck-path` attribute. -*KINDLEGEN*:: - Specifies path to KindleGen executable to use when producing KF8/Mobi. - Effect of this variable can be overriden with `-a ebook-kindlegen-path` attribute. - === EPUB3 Archive Structure Here's a sample manifest of files found in an EPUB3 document produced by {project-name}. @@ -548,11 +486,11 @@ To do so, use an attribute entry to set the value of the `imagesdir` attribute o == About the Theme -EPUB3 and KF8/MOBI files are styled using CSS3. +EPUB3 files are styled using CSS3. However, each e-reading platform honors a reduced set of CSS3 styles, and the styles they allow and how they implement them are rarely documented. All we've got to say is _thank goodness for CSS hacks, media queries and years of CSS experience!_ -The theme provided with {project-name} has been crafted to display EPUB3 and KF8/MOBI files as consistently as possible across the most common EPUB3 platforms and to degrade gracefully in select EPUB2 platforms. +The theme provided with {project-name} has been crafted to display EPUB3 files as consistently as possible across the most common EPUB3 platforms and to degrade gracefully in select EPUB2 platforms. The theme maintains readability regardless of the reading mode (i.e., day, night or sepia) or the display device's pixel density and screen resolution. The theme's CSS files are located in the [path]_data/style_ directory. @@ -595,23 +533,11 @@ Follow these steps to get it set up: $ export ADB=~/apps/android-sdk/platform-tools/adb -Now you can use the `adb-push-ebook` script provided by {project-name} to push the EPUB3 and KF8/MOBI files to your Android device. - -.Publish both EPUB3 and KF8 files to Android device - $ adb-push-ebook output/sample-book - -IMPORTANT: Don't include the file extension since the script will check for both .epub and .mobi files. +Now you can use the `adb push` to push the EPUB3 files to your Android device. -The `adb-push-ebook` script copies the files to the following locations on the device: +.Publish EPUB3 file to Android device + $ adb push output/sample-book.epub /sdcard -,=== -File type,Destination on Android device - -*.epub,/sdcard/ -*.mobi,/sdcard/Android/data/com.amazon.kindle/files/ -,=== - -Amazon Kindle should immediately detect the new file and display it in your “On Device” library. You'll have to manually import the EPUB3 into your e-reader of choice. == E-book Reader Recommendations and Quirks @@ -661,83 +587,3 @@ To see all the workarounds and why we chose certain style options, check out the * `-webkit-hyphens: auto` causes Kindle for Mac (and perhaps others) to crash * `text-rendering: optimizeLegibility` causes file to be rejected by KFP (and causes the text to disappear in some previewers) * Kindle Direct Publishing (KDP) strips out select font-related CSS rules (e.g., `font-family`) under certain conditions (for reasons that have proved nearly impossible to reverse engineer); the known workaround is to add a layer of indirection by using `@import` to hide the CSS files from the script - -=== Kindle Direct Publishing - -If you want to publish your book to the Amazon Kindle store, and have your styles and fonts preserved, you must use https://kdp.amazon.com[Kindle Direct Publishing]. -No other method of publishing to the Amazon Kindle store will leave your book intact. - -This workflow also allows you to preview the book the way your readers will see it. -So it's a good way to acceptance test your custom styles to discover which ones are honored and which ones are ignored. - -==== Look Inside - -The Amazon Kindle store offers a “Look Inside” feature for reader. -This so-called feature aims to give readers a glimpse at the contents of the book. -Sadly, it does no such thing. -Instead, it shows pages from the legacy MOBI document that kindlegen adds to your e-book file, not the higher fidelity KF8 document. -This means the preview won't look at all like what the Kindle reader or application will actually show. -Custom fonts, font-based icons, and most styles will be missing. - -This situation is unfortunate for authors. -What we recommend is to complain loudly to Amazon that they are hurting your sales by displaying a crippled version of your product. -Tell them that under no circumstances should they show an altered version of your product. -Another option is to contact Amazon to opt-out of this program. - -=== Send to Kindle - -WARNING: Don't use it! - -{uri-send-to-kindle}[Send to Kindle] is a tempting choice for transferring MOBI files to a Kindle device. -However, it's utterly broken. -If you use this tool, don't be surprised if you see missing font-based icons, default fonts, and other font and style errors in your manuscript. -It's known to strip out all the font files and break the encoding of the document. - -We *strongly* recommend you transfer the file to your device using either a USB cable or a sync service such as Dropbox. -Once transferred, Whispersync will detect the new file (usually looking in the Books folder) and add it to the “On Device” library. - -It's important to note that “Send to Kindle” is not reflective of the experience readers will have when shopping in the Kindle store. -If you use Kindle Direct Publishing (KDP) to publish your book, the integrity of your book will be preserved (to the degree that Amazon allows). - -//// -head-stop (default '.') -stack-head role (run-in is default) -signature role (sets hardbreaks option) - -subject-stop (default ':') -//// - -//// -== Device and Application Testing - -{project-name} has been tested on the following devices and applications. - -.Computers -|=== -|Device |OS |Resolution |ppi |Browsers |Readium |Gitden |Kindle - -|Asus -|Fedora 17 -|no x no -| -|Chrome x -|Readium - -Asus, Fedora 20, display resolution, Chrome x, Readium -Ideapad Y460 |Fedora 20 |1366 x 768 (16:9) | -PC, Windows X, -|=== - -.Tablets -|=== -Asus Transformer, Android x, display resolution, Aldiko, Kindle, Readium, Readmill -Nexus, -|=== - -.Phones -|=== -HTC Sensation, Android x, display resolution, xxxx -Nexus , -|=== - -//// diff --git a/lib/asciidoctor-epub3/converter.rb b/lib/asciidoctor-epub3/converter.rb index 091f8d0..ffab410 100644 --- a/lib/asciidoctor-epub3/converter.rb +++ b/lib/asciidoctor-epub3/converter.rb @@ -7,8 +7,7 @@ require_relative 'font_icon_map' module Asciidoctor module Epub3 - # Public: The main converter for the epub3 backend that handles packaging the - # EPUB3 or KF8 publication file. + # Public: The main converter for the epub3 backend that handles packaging the EPUB3 publication file. class Converter include ::Asciidoctor::Converter include ::Asciidoctor::Logging @@ -17,15 +16,14 @@ module Asciidoctor register_for 'epub3' def write(output, target) - epub_file = @format == :kf8 ? %(#{::Asciidoctor::Helpers.rootname target}-kf8.epub) : target - output.generate_epub epub_file - logger.debug %(Wrote #{@format.upcase} to #{epub_file}) + output.generate_epub target + logger.debug %(Wrote to #{target}) if @extract - extract_dir = epub_file.sub EPUB_EXTENSION_RX, '' + extract_dir = target.sub EPUB_EXTENSION_RX, '' ::FileUtils.remove_dir extract_dir if ::File.directory? extract_dir ::Dir.mkdir extract_dir ::Dir.chdir extract_dir do - ::Zip::File.open epub_file do |entries| + ::Zip::File.open target do |entries| entries.each do |entry| next unless entry.file? @@ -36,15 +34,12 @@ module Asciidoctor end end end - logger.debug %(Extracted #{@format.upcase} to #{extract_dir}) + logger.debug %(Extracted to #{extract_dir}) end - if @format == :kf8 - # QUESTION: shouldn't we validate this epub file too? - distill_epub_to_mobi epub_file, target, @compress - elsif @validate - validate_epub epub_file - end + return unless @validate + + validate_epub target end CSV_DELIMITED_RX = /\s*,\s*/.freeze @@ -80,14 +75,6 @@ module Asciidoctor TO_HTML_SPECIAL_CHARS_RX = /[#{TO_HTML_SPECIAL_CHARS_MAP.keys.join}]/.freeze EPUB_EXTENSION_RX = /\.epub$/i.freeze - KINDLEGEN_COMPRESSION = { - '0' => '-c0', - '1' => '-c1', - '2' => '-c2', - 'none' => '-c0', - 'standard' => '-c1', - 'huffdic' => '-c2' - }.freeze QUOTE_TAGS = begin tags = { @@ -109,7 +96,7 @@ module Asciidoctor def initialize(backend, opts = {}) super basebackend 'html' - outfilesuffix '.epub' # dummy outfilesuffix since it may be .mobi + outfilesuffix '.epub' htmlsyntax 'xml' end @@ -158,19 +145,16 @@ module Asciidoctor end def convert_document(node) - @format = node.attr('ebook-format').to_sym - @validate = node.attr? 'ebook-validate' @extract = node.attr? 'ebook-extract' @compress = node.attr 'ebook-compress' - @kindlegen_path = node.attr 'ebook-kindlegen-path' @epubcheck_path = node.attr 'ebook-epubcheck-path' @xrefs_seen = ::Set.new @media_files = {} @footnotes = [] @book = GEPUB::Book.new 'EPUB/package.opf' - @book.epub_backward_compat = @format != :kf8 + @book.epub_backward_compat = true @book.language node.attr('lang', 'en'), id: 'pub-language' if node.attr? 'uuid' @@ -239,7 +223,7 @@ module Asciidoctor landmarks = [] front_cover = add_cover_page node, 'front-cover' - if front_cover.nil? && @format != :kf8 && node.doctype == 'book' + if front_cover.nil? && node.doctype == 'book' # TODO(#352): add textual front cover similar to PDF end @@ -289,9 +273,9 @@ module Asciidoctor } end - nav_item.add_content postprocess_xhtml(nav_doc(node, toc_items, landmarks, outlinelevels)) + nav_item.add_content nav_doc(node, toc_items, landmarks, outlinelevels).to_ios # User is not supposed to see landmarks, so pass empty array here - toc_item&.add_content postprocess_xhtml(nav_doc(node, toc_items, [], toclevels)) + toc_item&.add_content nav_doc(node, toc_items, [], toclevels).to_ios # NOTE: gepub doesn't support building a ncx TOC with depth > 1, so do it ourselves toc_ncx = ncx_doc node, toc_items, outlinelevels @@ -406,10 +390,8 @@ module Asciidoctor end header = if title || subtitle - %(<header> -<div class="chapter-header"> + %(<header class="chapter-header"> #{byline}<h1 class="chapter-title">#{title}#{subtitle ? %(<small class="subtitle">#{subtitle}</small>) : ''}</h1> -</div> </header>) else '' @@ -419,7 +401,6 @@ module Asciidoctor # in order to avoid style duplication across chapter files linkcss = true - # NOTE: kindlegen seems to mangle the <header> element, so we wrap its content in a div lines = [%(<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xmlns:mml="http://www.w3.org/1998/Math/MathML" xml:lang="#{lang = node.document.attr 'lang', @@ -455,9 +436,7 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { unless (fns = node.document.footnotes - @footnotes).empty? @footnotes += fns - # NOTE: kindlegen seems to mangle the <footer> element, so we wrap its content in a div - lines << '<footer> -<div class="chapter-footer"> + lines << '<footer class="chapter-footer"> <div class="footnotes">' fns.each do |footnote| lines << %(<aside id="note-#{footnote.index}" epub:type="footnote"> @@ -465,7 +444,6 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { </aside>) end lines << '</div> -</div> </footer>' end @@ -479,7 +457,7 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { lines << '</body> </html>' - chapter_item.add_content postprocess_xhtml lines * LF + chapter_item.add_content((lines * LF).to_ios) epub_properties = node.attr 'epub-properties' chapter_item.add_property 'svg' if epub_properties&.include? 'svg' @@ -1386,7 +1364,6 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { end def add_theme_assets(doc) - format = @format workdir = if doc.attr? 'epub3-stylesdir' stylesdir = doc.attr 'epub3-stylesdir' # FIXME: make this work for Windows paths!! @@ -1404,13 +1381,7 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { # TODO: improve design/UX of custom theme functionality, including custom fonts %w[epub3 epub3-css3-only].each do |f| css = load_css_file File.join(workdir, %(#{f}.scss)) - if format == :kf8 - # NOTE: add layer of indirection so Kindle Direct Publishing (KDP) doesn't strip font-related CSS rules - @book.add_item %(styles/#{f}.css), content: %(@import url("#{f}-proxied.css");).to_ios - @book.add_item %(styles/#{f}-proxied.css), content: css.to_ios - else - @book.add_item %(styles/#{f}.css), content: css.to_ios - end + @book.add_item %(styles/#{f}.css), content: css.to_ios end syntax_hl = doc.syntax_highlighter @@ -1433,15 +1404,12 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { @book.add_item 'styles/epub3-fonts.css', content: font_css.to_ios unless font_files.empty? # NOTE: metadata property in oepbs package manifest doesn't work; must use proprietary iBooks file instead - # (@book.metadata.add_metadata 'meta', 'true')['property'] = 'ibooks:specified-fonts' unless format == :kf8 - unless format == :kf8 - @book.add_optional_file 'META-INF/com.apple.ibooks.display-options.xml', '<?xml version="1.0" encoding="UTF-8"?> + @book.add_optional_file 'META-INF/com.apple.ibooks.display-options.xml', '<?xml version="1.0" encoding="UTF-8"?> <display_options> <platform name="*"> <option name="specified-fonts">true</option> </platform> </display_options>'.to_ios - end font_files.each do |font_file| @book.add_item font_file, content: File.join(DATA_DIR, font_file) @@ -1486,8 +1454,6 @@ document.addEventListener('DOMContentLoaded', function(event, reader) { return nil end - return nil if @format == :kf8 - unless !image_attrs.empty? && (width = image_attrs['width']) && (height = image_attrs['height']) width = 1050 height = 1600 @@ -1522,9 +1488,9 @@ body > svg { width="100%" height="100%" viewBox="0 0 #{width} #{height}" preserveAspectRatio="xMidYMid meet"> <image width="#{width}" height="#{height}" xlink:href="#{image_href}"/> </svg></body> -</html>).to_ios +</html>) - @book.add_ordered_item %(#{name}.xhtml), content: content, id: name + @book.add_ordered_item %(#{name}.xhtml), content: content.to_ios, id: name end def get_frontmatter_files(doc, workdir) @@ -1559,7 +1525,7 @@ body > svg { front_matter_content = ::File.read front_matter front_matter_file = File.basename front_matter, '.html' - item = @book.add_ordered_item "#{front_matter_file}.xhtml", content: (postprocess_xhtml front_matter_content) + item = @book.add_ordered_item "#{front_matter_file}.xhtml", content: front_matter_content.to_ios item.add_property 'svg' if SVG_IMG_SNIFF_RX =~ front_matter_content # Store link to first frontmatter page result = item if result.nil? @@ -1615,8 +1581,8 @@ body > svg { </head> <body> <section class="chapter"> -<header> -<div class="chapter-header"><h1 class="chapter-title"><small class="subtitle">#{doc.attr 'toc-title'}</small></h1></div> +<header class="chapter-header"> +<h1 class="chapter-title"><small class="subtitle">#{doc.attr 'toc-title'}</small></h1> </header> <nav epub:type="toc" id="toc">)] lines << (nav_level items, [depth, 0].max) @@ -1738,72 +1704,6 @@ body > svg { sass_engine.render end - def postprocess_xhtml(content) - return content.to_ios unless @format == :kf8 - - # TODO: convert regular expressions to constants - content - .gsub(/<img([^>]+) style="width: (\d\d)%;"/, '<img\1 style="width: \2%; height: \2%;"') - .gsub(%r{<script type="text/javascript">.*?</script>\n?}m, '') - .to_ios - end - - def build_kindlegen_command - unless @kindlegen_path.nil? - logger.debug %(Using ebook-kindlegen-path attribute: #{@kindlegen_path}) - return [@kindlegen_path] - end - - unless (result = ENV.fetch('KINDLEGEN', nil)).nil? - logger.debug %(Using KINDLEGEN env variable: #{result}) - return [result] - end - - begin - require 'kindlegen' unless defined? ::Kindlegen - result = ::Kindlegen.command.to_s - logger.debug %(Using KindleGen from gem: #{result}) - [result] - rescue LoadError => e - logger.debug %(#{e}; Using KindleGen from PATH) - [%(kindlegen#{::Gem.win_platform? ? '.exe' : ''})] - end - end - - def distill_epub_to_mobi(epub_file, target, compress) - mobi_file = ::File.basename target.sub(EPUB_EXTENSION_RX, '.mobi') - compress_flag = KINDLEGEN_COMPRESSION[if compress - compress.empty? ? '1' : compress.to_s - else - '0' - end] - - argv = build_kindlegen_command + ['-dont_append_source', compress_flag, '-o', mobi_file, epub_file].compact - begin - # This duplicates Kindlegen.run, but we want to override executable - out, err, res = Open3.capture3(*argv) do |r| - r.force_encoding 'UTF-8' if ::Gem.win_platform? && r.respond_to?(:force_encoding) - end - rescue Errno::ENOENT => e - raise 'Unable to run KindleGen. Either install the kindlegen gem or place `kindlegen` executable on PATH or set KINDLEGEN environment variable with path to it', - cause: e - end - - out.each_line do |line| - log_line line - end - err.each_line do |line| - log_line line - end - - output_file = ::File.join ::File.dirname(epub_file), mobi_file - if res.success? - logger.debug %(Wrote MOBI to #{output_file}) - else - logger.error %(KindleGen failed to write MOBI to #{output_file}) - end - end - def build_epubcheck_command unless @epubcheck_path.nil? logger.debug %(Using ebook-epubcheck-path attribute: #{@epubcheck_path}) @@ -1875,27 +1775,6 @@ body > svg { end end - class NumericIdGenerator - def initialize - @counter = 1 - end - - # @param node [Asciidoctor::AbstractNode] - # @return [void] - def generate_id(node) - if node.chapter? || node.is_a?(Asciidoctor::Document) - node.id = %(_generated_id_#{@counter}) - @counter += 1 - end - - # Recurse - node.blocks.each do |subnode| - # dlist contains array of *arrays* of blocks, so just skip them - generate_id subnode if subnode.is_a?(Asciidoctor::AbstractBlock) - end - end - end - Extensions.register do if (document = @document).backend == 'epub3' document.set_attribute 'listing-caption', 'Listing' @@ -1904,33 +1783,22 @@ body > svg { document.set_attribute 'pygments-style', 'bw' unless document.attr? 'pygments-style' document.set_attribute 'rouge-style', 'bw' unless document.attr? 'rouge-style' - case (ebook_format = document.attributes['ebook-format']) - when 'epub3', 'kf8' - # all good - when 'mobi' - ebook_format = document.attributes['ebook-format'] = 'kf8' - else - # QUESTION: should we display a warning? - ebook_format = document.attributes['ebook-format'] = 'epub3' - end - document.attributes[%(ebook-format-#{ebook_format})] = '' + # Backward compatibility for documents that were created before we dropped MOBI support + document.set_attribute 'ebook-format', 'epub3' + document.set_attribute 'ebook-format-epub3', '' # Enable generation of section ids because we use them for chapter filenames document.set_attribute 'sectids' treeprocessor do process do |doc| - if ebook_format == 'kf8' - # Kindlegen doesn't support unicode ids - NumericIdGenerator.new.generate_id doc - else - # :sectids: doesn't generate id for top-level section (why?), do it manually - doc.id = Section.generate_id(doc.first_section&.title || doc.attr('docname') || 'document', doc) if doc.id.nil_or_empty? + # :sectids: doesn't generate id for top-level section (why?), do it manually + doc.id = Section.generate_id(doc.first_section&.title || doc.attr('docname') || 'document', doc) if doc.id.nil_or_empty? - if (preamble = doc.blocks[0]) && preamble.context == :preamble && preamble.id.nil_or_empty? - # :sectids: doesn't generate id for preamble (because it is not a section), do it manually - preamble.id = Section.generate_id(preamble.title || 'preamble', doc) - end + if (preamble = doc.blocks[0]) && preamble.context == :preamble && preamble.id.nil_or_empty? + # :sectids: doesn't generate id for preamble (because it is not a section), do it manually + preamble.id = Section.generate_id(preamble.title || 'preamble', doc) end + nil end end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index fd790a3..032dc29 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -37,17 +37,6 @@ describe 'asciidoctor-epub3' do expect(File).to exist(out_file) end - it 'converts sample book to mobi' do - in_file = example_file 'sample-book.adoc' - out_file = temp_file 'sample-book.mobi' - - _, err, res = to_mobi in_file, out_file - expect(res.exitstatus).to eq(0) - expect(err).not_to include 'ERROR' - expect(err).not_to include 'invalid reference' - expect(File).to exist(out_file) - end - it 'prints errors to stderr when converts invalid book to epub' do _, err, res = to_epub fixture_file('invalid.adoc'), temp_file('invalid.epub') expect(res.exitstatus).to eq(0) @@ -57,17 +46,6 @@ describe 'asciidoctor-epub3' do expect(err).to include 'EPUB validation failed' end - it 'prints errors to stderr when converts invalid book to mobi' do - _, err, res = to_mobi fixture_file('invalid.adoc'), temp_file('invalid.mobi') - expect(err).to include 'ERROR' - expect(res.exitstatus).to eq(0) - end - - def to_mobi(in_file, out_file) - skip_unless_has_kindlegen - run_command asciidoctor_epub3_bin, '-a', 'ebook-format=mobi', in_file.to_s, '-o', out_file.to_s - end - def to_epub(in_file, out_file = nil) argv = asciidoctor_epub3_bin + ['-a', 'ebook-validate', in_file.to_s] argv += ['-o', out_file.to_s] unless out_file.nil? diff --git a/spec/converter_spec.rb b/spec/converter_spec.rb index 273cbd9..454f6f1 100644 --- a/spec/converter_spec.rb +++ b/spec/converter_spec.rb @@ -8,10 +8,6 @@ describe Asciidoctor::Epub3::Converter do expect(to_epub(fixture_file('empty.adoc'))).not_to be_nil end - it 'converts empty file to mobi without exceptions' do - expect(to_mobi(fixture_file('empty.adoc'))).not_to be_nil - end - it 'converts empty heredoc document to epub without exceptions' do expect(to_epub('')).not_to be_nil end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 941c643..4d61d2f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -61,12 +61,6 @@ RSpec.configure do |config| examples_dir.join(*path) end - def skip_unless_has_kindlegen - require 'kindlegen' - rescue LoadError - skip 'kindlegen gem is unavailable' - end - def convert(input, opts = {}) opts[:backend] = 'epub3' opts[:header_footer] = true @@ -89,15 +83,6 @@ RSpec.configure do |config| book = GEPUB::Book.parse output [book, output] end - - def to_mobi(input, opts = {}) - skip_unless_has_kindlegen - (opts[:attributes] ||= {})['ebook-format'] = 'mobi' - doc = convert input, opts - output = Pathname.new(doc.attr('outfile')).sub_ext '.mobi' - expect(output).to exist - output - end end RSpec::Matchers.define :have_size do |expected| |
