feat: added dockerfile, made the guide closable

This commit is contained in:
Stefan 2026-08-13 23:43:33 +03:00
parent 99882bb80a
commit 1ac80e2a56
5 changed files with 58 additions and 7 deletions

5
.dockerignore Normal file
View file

@ -0,0 +1,5 @@
node_modules
dist
uploads
.env
.git

21
Dockerfile Normal file
View file

@ -0,0 +1,21 @@
# Build stage: compile TypeScript
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
# Runtime stage: production deps only
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
COPY public ./public
RUN mkdir -p uploads && chown node:node uploads
USER node
EXPOSE 3000
CMD ["node", "dist/app.js"]

View file

@ -1,15 +1,25 @@
{ {
"name": "send-to-ereader", "name": "send-to-ereader",
"version": "0.2.0", "version": "0.2.2",
"description": "Convert web articles to EPUB and email them to your e-reader, or upload a file (EPUB, PDF, etc.) directly.", "description": "Convert web articles to EPUB and email them to your e-reader, or upload a file (EPUB, PDF, etc.) directly.",
"homepage": "https://atanasov.fi", "homepage": "https://atanasov.fi",
"repository": {
"type": "git",
"url": "https://git.atanasov.fi/atanasov/send-to-ereader.git"
},
"main": "app.js", "main": "app.js",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "tsx watch ./src/app.ts", "dev": "tsx watch ./src/app.ts",
"build": "tsc", "build": "tsc",
"start": "node dist/app.js", "start": "node dist/app.js",
"prod": "npm run build && npm run start" "prod": "npm run build && npm run start",
"build-prod-push": "docker buildx build --push --platform linux/amd64 -t $(npm pkg get config.docker.registry | xargs)/$(npm pkg get name | xargs):$(npm pkg get version | xargs) -t $(npm pkg get config.docker.registry | xargs)/$(npm pkg get name | xargs):latest ."
},
"config": {
"docker": {
"registry": "git.atanasov.fi/atanasov"
}
}, },
"keywords": [], "keywords": [],
"author": "Stefan Atanasov", "author": "Stefan Atanasov",

View file

@ -70,6 +70,16 @@
font-size: 14px; font-size: 14px;
} }
.setup-info summary {
cursor: pointer;
}
.setup-info summary h2 {
display: inline;
font-size: 15px;
margin: 0;
}
.setup-info code { .setup-info code {
background: #fff; background: #fff;
padding: 2px 4px; padding: 2px 4px;
@ -209,8 +219,8 @@
<main> <main>
<article class="container"> <article class="container">
<section class="setup-info"> <details class="setup-info">
<h2>guide</h2> <summary><h2>guide</h2></summary>
<ol> <ol>
<li> <li>
whitelist <code>send@read.atanasov.fi</code> on your device — one-time setup: whitelist <code>send@read.atanasov.fi</code> on your device — one-time setup:
@ -275,7 +285,7 @@
<code>localStorage</code> for future use; nothing is stored on the server <code>localStorage</code> for future use; nothing is stored on the server
</li> </li>
</ul> </ul>
</section> </details>
<section class="send-section"> <section class="send-section">
<div class="input-group"> <div class="input-group">
@ -344,7 +354,7 @@
<footer> <footer>
<p id="credits"> <p id="credits">
v 0.2.0 v 0.2.2
<a <a
href="https://atanasov.fi" href="https://atanasov.fi"
target="_blank" target="_blank"
@ -353,7 +363,7 @@
> >
<a <a
href="https://codeberg.org/atanasoff/send-to-ereader" href="https://git.atanasov.fi/atanasov/send-to-ereader"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
>source</a >source</a

View file

@ -3,6 +3,7 @@ import { JSDOM } from "jsdom";
import { Readability } from "@mozilla/readability"; import { Readability } from "@mozilla/readability";
import nodemailer from "nodemailer"; import nodemailer from "nodemailer";
import path from "path"; import path from "path";
import os from "os";
import fs from "fs"; import fs from "fs";
import sanitizeFilename from "sanitize-filename"; import sanitizeFilename from "sanitize-filename";
import { EpubOptions, EPub } from "@lesjoursfr/html-to-epub"; import { EpubOptions, EPub } from "@lesjoursfr/html-to-epub";
@ -151,6 +152,10 @@ async function createEpub(article: ArticleContent): Promise<string> {
img { max-width: 100%; height: auto; } img { max-width: 100%; height: auto; }
`, `,
verbose: false, verbose: false,
// Write scratch files to the system temp dir instead of the library's
// default inside node_modules, which is not writable by the non-root
// user in the Docker image.
tempDir: os.tmpdir(),
}; };
const epub = new EPub(options, epubPath); const epub = new EPub(options, epubPath);