From: Julien Moutinho Date: Thu, 6 Feb 2025 20:53:46 +0000 (+0100) Subject: init X-Git-Url: https://git.sourcephile.fr/julm/books.git/commitdiff_plain?ds=sidebyside init --- f3db771f8015a03de506cd39ee18c6c9bf33f293 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/calibre/.gitattributes b/calibre/.gitattributes new file mode 100644 index 0000000..a3e2527 --- /dev/null +++ b/calibre/.gitattributes @@ -0,0 +1,2 @@ +*.epub filter=git-crypt diff=git-crypt +*.pdf filter=git-crypt diff=git-crypt diff --git a/calibre/J. K. Rowling/Harry Potter and the Philosopher's Stone (484)/Harry Potter and the Philosopher's Stone - J. K. Rowling.epub b/calibre/J. K. Rowling/Harry Potter and the Philosopher's Stone (484)/Harry Potter and the Philosopher's Stone - J. K. Rowling.epub new file mode 100644 index 0000000..cd7a1a2 Binary files /dev/null and b/calibre/J. K. Rowling/Harry Potter and the Philosopher's Stone (484)/Harry Potter and the Philosopher's Stone - J. K. Rowling.epub differ diff --git a/calibre/J. K. Rowling/Harry Potter and the Philosopher's Stone (484)/filter b/calibre/J. K. Rowling/Harry Potter and the Philosopher's Stone (484)/filter new file mode 100755 index 0000000..da9a464 --- /dev/null +++ b/calibre/J. K. Rowling/Harry Potter and the Philosopher's Stone (484)/filter @@ -0,0 +1,42 @@ +#!/usr/bin/env nix +#! nix shell --impure --expr `` +#! nix with (builtins.getFlake "git+file://${toString ./../..}/..").packages.${builtins.currentSystem}; +#! nix [ +#! nix (haskellPackages.ghcWithPackages ( +#! nix haskellPackages: [ +#! nix haskellPackages.pandoc-types +#! nix ] +#! nix )) +#! nix ] +#! nix `` +#! nix --command runhaskell + +{-#LANGUAGE OverloadedStrings#-} +{-#LANGUAGE ViewPatterns #-} +import Text.Pandoc.JSON +import Data.List qualified as List +import Data.Text qualified as Text + +main :: IO () +main = toJSONFilter filt + +filt :: Block -> Block +-- Put chapter images into the chapter +filt (Div as@(_, ["Section1"], _) es) = Div as (fixChapterImage es) +-- Remove useless images +filt (Para (Image _ _ ("Images/philos0.jpg", _):_)) = Para [] +filt x = x + +fixChapterImage (p@(Para + [ Span + ( _ , _ , _ ) + (Image ( _ , _ , _ ) _ ( Text.isPrefixOf "Images/Chapter" -> True , _ ) + :_) + ]) + :h@Header{} + :xs + ) = h:p:xs +fixChapterImage (x:xs) = x:fixChapterImage xs +fixChapterImage [] = [] + +-- vim: syntax=haskell diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3f81ec3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,87 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1734323986, + "narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "394571358ce82dff7411395829aa6a3aad45b907", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1737465171, + "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..9b92b7c --- /dev/null +++ b/flake.nix @@ -0,0 +1,61 @@ +{ + description = "books"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs"; + pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix"; + }; + + outputs = + inputs: + let + inherit (inputs.nixpkgs) lib; + forAllSystems = + f: + lib.genAttrs lib.systems.flakeExposed ( + system: + f rec { + inherit system; + pkgs = inputs.nixpkgs.legacyPackages.${system}; + } + ); + in + { + # nix -L build .#hello + packages = forAllSystems ({ pkgs, ... }: pkgs); + + # nix -L develop or direnv allow + devShell = forAllSystems ( + { + pkgs, + system, + ... + }: + pkgs.mkShell { + name = "shell"; + src = null; + buildInputs = [ + pkgs.fontconfig + #pkgs.gitFull + pkgs.jq + pkgs.pandoc + pkgs.reuse + pkgs.shellcheck + ]; + inherit (inputs.self.checks.${system}.pre-commit-check) shellHook; + } + ); + + # nix flake check + checks = forAllSystems ( + args: with args; { + pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { + src = inputs.self; + hooks = { + nixfmt-rfc-style.enable = true; + }; + }; + } + ); + }; +} diff --git a/scripts/epub2pdf.sh b/scripts/epub2pdf.sh new file mode 100755 index 0000000..c84c3c5 --- /dev/null +++ b/scripts/epub2pdf.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env nix +#! nix shell --impure --expr `` +#! nix with (builtins.getFlake "git+file://${toString ./.}/..").packages.${builtins.currentSystem}; +#! nix let fonts = [ +#! nix pkgs.comic-mono +#! nix pkgs.crimson +#! nix pkgs.dejavu_fonts +#! nix pkgs.fira-code +#! nix pkgs.freefont_ttf +#! nix pkgs.gyre-fonts # TrueType substitutes for standard PostScript fonts +#! nix pkgs.hack-font +#! nix pkgs.liberation_ttf +#! nix pkgs.lmodern +#! nix pkgs.noto-fonts-emoji +#! nix pkgs.tex-gyre.adventor +#! nix pkgs.tex-gyre.bonum +#! nix pkgs.tex-gyre.chorus +#! nix pkgs.tex-gyre.cursor +#! nix pkgs.tex-gyre.heros +#! nix pkgs.tex-gyre.pagella +#! nix pkgs.tex-gyre.schola +#! nix pkgs.tex-gyre.termes +#! nix pkgs.unifont +#! nix ]; in +#! nix [ +#! nix (pkgs.writeShellScriptBin "interpreter" '' +#! nix # used by luaotfload (lualatex) +#! nix export OSFONTDIR="${lib.concatStringsSep "//:" (map toString fonts)}" +#! nix exec bash "$@" +#! nix '') +#! nix pandoc +#! nix pdftk +#! nix qpdf +#! nix (pkgs.texlive.combine { +#! nix inherit (pkgs.texlive) +#! nix collection-fontsrecommended +#! nix collection-langenglish +#! nix collection-langfrench +#! nix collection-latexrecommended +#! nix collection-luatex +#! nix pdfbook2 +#! nix pdfcrop +#! nix pdfjam +#! nix scheme-basic +#! nix tex-gyre +#! nix ; +#! nix }) +#! nix ] +#! nix `` +#! nix --command interpreter + +epubPath=$1 +epubDir=$(realpath -e "$(dirname "$epubPath")") +styleDir=$(realpath -e "$(dirname "$0")")/styles +outDir=$epubDir/pdf +pdfFile="$outDir"/out.pdf +rm -rf "$outDir" +mkdir -p "$outDir" + +# Converting EPUB to PDF +set -eux +pandoc \ + --embed-resources \ + --include-in-header "$styleDir"/epub.header.tex \ + --filter "$epubDir"/filter \ + --number-sections \ + --pdf-engine lualatex \ + --standalone \ + --toc \ + --toc-depth 6 \ + --top-level-division chapter \ + -V documentclass=scrbook \ + -V classoption=english \ + -V mainfont="TeX Gyre Termes" \ + -V fontsize=13pt \ + -V papersize=a5 \ + -i "$epubPath" \ + -t pdf \ + -o "$pdfFile" + +# Slicing on chapters and splitting into chunks of at most 18 pages (for easy binding) + mkdir -p "$outDir"/sections + pdftk "$pdfFile" dump_data | grep '^BookmarkPageNumber:' | + { + sectionNum=1 + sectionBegin=1 + splitSection () { + qpdf \ + "$pdfFile" \ + "$outDir"/sections/sectionNum="$sectionNum".pages="$sectionPages".chunk=%d.pdf \ + --pages "$pdfFile" "$sectionPages" -- \ + --split-pages=18 + } + while read -r _BookmarkPageNumber sectionEnd; do + test "$sectionEnd" != 1 || continue + sectionPages=$sectionBegin-$((sectionEnd-1)) + splitSection + sectionNum=$((sectionNum+1)) + sectionBegin=$sectionEnd + done + sectionPages="$sectionBegin"-r1 + splitSection + } + +# Converting to booklet + find "$outDir"/sections -type f | + sort -n | + while read -r pdfSection; do + # Margins have already been set correctly by the geometry package in header.tex + # pdfbook2 fails to move the .pdf over filesystems + pdfbook2 --no-crop \ + --paper "${paper:-a4paper}" \ + --outer-margin "${outerMargin:-80}" \ + --inner-margin "${innerMargin:-150}" \ + --top-margin "${topmargin:-30}" \ + --bottom-margin "${bottomMargin:-30}" \ + "$pdfSection" + rm "$pdfSection" + + # Split odd and even pages to print in the same direction + pdftk "${pdfSection%.pdf}"-book.pdf cat oddSouth output "${pdfSection%.pdf}".book.odds.pdf + pdftk "${pdfSection%.pdf}"-book.pdf cat even output "${pdfSection%.pdf}".book.even.pdf + rm "${pdfSection%.pdf}"-book.pdf + done diff --git a/scripts/styles/epub.header.tex b/scripts/styles/epub.header.tex new file mode 100644 index 0000000..68e3eba --- /dev/null +++ b/scripts/styles/epub.header.tex @@ -0,0 +1,5 @@ +% Geometry for the booklet +\usepackage[portrait, left=1.5cm, right=1.5cm, top=2.5cm, bottom=2cm, headheight=1.5cm, headsep=1cm, footskip=1cm, marginparsep=0pt, marginparwidth=0pt, bindingoffset=1cm, twoside]{geometry} + +% No title +\renewcommand{\maketitle}{}