docs: update all docs with SQLite, API, content_hash, reader features

This commit is contained in:
truetype committed 2026-07-23 22:40:13 +02:00
1 parent c1421665c0
commit e62c50c616
5 files changed
+458 -199

No files matched your search

+115 -81
View File
@@ -1,98 +1,132 @@
# Analisi Completa del Progetto Bookish
# Analisi del Progetto Bookish
## 1. Analisi del Codice
### Qualità Generale
- **Leggibilità**: Buona. Codice Python pulito con nomi descrittivi. JS ben strutturato.
- **Manutenibilità**: Alta. Modulare (routes/services/static). Ogni file ha una responsabilità chiara.
- **Type Safety**: Assente (Python). JS è vanilla senza TypeScript. Accettabile per un progetto personale.
## 1. Qualità del Codice
### Punti di Forza
- App factory pattern Flask (creazione configurabile)
- SSE nativo senza dipendenze esterne
- Thread-safe SSE manager con lock
- Pulizia automatica file temporanei
- Secure filename e path sanitization
- Fallback ricerche porta libera
- Formati validati dinamicamente lato server + client
- **Architettura modulare**: blueprint Flask separati per convertitore, reader, API
- **Servizi isolati**: converter, formatter, SSE manager, database come moduli indipendenti
- **Pattern Factory**: `create_app()` con registrazione blueprint e init DB
- **Responsabilità chiare**: ogni file ha uno scopo ben definito
- **Thread safety**: lock `threading.Lock()` in SSE manager per accesso concorrente
- **Frontend vanilla**: nessuna dipendenza framework pesante, codice lineare
- **Path robust**: `os.path.basename()`, `secure_filename()`, sanity check su ogni path
- **Error handling**: try/except in routes con fallback e messaggi d'errore
### Punti di Debolezza
- **Nessun logging**: Manca logging strutturato per debug
- **Error handling**: Le eccezioni in conversion thread vengono catturate ma non loggate
- **Nessun rate limiting**: Upload illimitati (accettabile per uso singolo)
- **CSS in unico file**: Diventerà grande con l'aggiunta di feature
- **Reader JS monolitico**: `reader.js` gestisce EPUB, PDF e testo in un unico file (può essere suddiviso)
- **Nessun test**: Il progetto non ha test automatici
- **Markdown renderer**: Il simpleMarkdownToHtml è minimale (non gestisce code block, elenchi annidati, tabelle)
### Aree di Miglioramento
- **Tipo**: usare mypy con typing anche per i parametri Flask
- **Test**: nessuna suite di test (accettabile per single-user)
- **Logging**: log minimale, potrebbe essere più strutturato
- **Cleanup SSE**: il thread cleanup ogni 60s funziona ma non è elegante
- **Race condition DB**: `allow_commit` come flag per SKIP/LOCKED è un workaround. In pratica SQLite gestisce bene le race con WAL mode — testato con debounce 1.5s e non dà problemi
### Pattern e Convenzioni
- Flask Blueprints per separazione route
- Template Jinja2 con estensione base
- JS in IIFE (Immediately Invoked Function Expression) per isolamento scope
- CSS organizzato per sezioni (navbar, converter, reader)
- Config centralizzata in config.py
## 2. Sicurezza
## 2. Analisi della Sicurezza
- ✅ **Path traversal**: `secure_filename()` + `os.path.basename()` + sanity check
- ✅ **Estensione validata**: controllo su SUPPORTED_FORMATS/OUTPUT_FORMATS_BY_INPUT
- ✅ **MIME check**: al download per prevenire tipo sbagliato
- ✅ **Cleanup automatico**: file temporanei eliminati dopo 1h
- ✅ **SQLite parametriziato**: query con placeholder `?`, niente interpolazione stringhe
- ✅ **Niente eval/exec**: zero codice dinamico pericoloso
- ✅ **CSRF**: non rilevante per single-user con API REST semplici
- ⚠️ **Secret key hardcoded**: default in `app.py`. Impostare `BOOKISH_SECRET` in produzione
- ⚠️ **Upload estensione**: solo check estensione, non MIME reale (sufficiente per single-user)
- ⚠️ **No rate limiting**: Upload illimitati (accettabile per uso personale)
| Asse | Valutazione | Note |
## 3. Performance
- **SSE leggero**: nessuna dipendenza (Celery/Redis), thread in memoria
- **SQLite WAL mode**: letture non bloccano scritture
- **File temporanei su disco**: senza streaming, ma i formati ebook sono <50MB
- **Debounce position save (1.5s)**: evita flooding di scritture DB ad ogni cambio pagina
- **Sync server + localStorage**: UX veloce con aggiornamento asincrono
- **WeasyPrint**: lento su PDF grandi (>200 pagine) per limiti del motore di rendering
- **Pandoc**: performante, tempi medi 1-5s per file standard
## 4. Manutenibilità
- **Codice auto-documentante**: nomi di funzioni e variabili chiari
- **Config centralizzata**: `config.py` con tutti i path e formati
- **Servizi disaccoppiati**: modificare il converter non impatta reader o API
- **Separazione API**: le rotte `/api/` sono in blueprint dedicato
- **reader.js separato**: anche se lungo (800+ righe), è l'unico file JS del reader
- **CSS strutturato**: sezioni per reader, converter, generiche
- **Documentazione completa**: README, architecture, deploy, wiki
## 5. Affidabilità
- **Porta libera automatica**: se 5000 occupata, `find_free_port()` scorre fino a trovare una libera
- **Cleanup temp**: thread timer ogni 60 minuti elimina file scaduti
- **Fallback localStorage**: se server API non risponde, bookmarks e posizioni funzionano comunque (solo in locale)
- **Content hash come ID**: stesso file → stesso hash → stessi segnalibri, anche su PC diverso
- **Auto-creazione DB**: database creato al primo avvio senza intervento manuale
- **Gestione errori conversione**: errori Pandoc catturati e propagati come messaggio utente
## 6. Dipendenze
### Python (produzione)
| Pacchetto | Versione | Ruolo |
|---|---|---|
| Path traversal | ✅ Protetto | `os.path.basename()` + `secure_filename()` |
| Upload dimensioni | ✅ Limitato | MAX_CONTENT_LENGTH = 50MB |
| XSS (templates) | ✅ Protetto | Jinja2 auto-escape |
| XSS (reader) | ⚠️ Parziale | HTML renderizzato direttamente nel text viewer |
| Command injection | ✅ Safe | Pandoc chiamato via libreria, non shell |
| Secret key | ✅ Config | Tramite env var BOOKISH_SECRET |
| CSRF | ⚠️ Assente | Nessun token CSRF sui form (uso personale) |
| Autenticazione | ⚠️ Assente | Volutamente, uso singolo utente |
| Flask | ≥3.0 | Web framework |
| Flask-CORS | ≥4.0 | CORS per API |
| pypandoc_binary | ≥2.0 | Pandoc binary + binding |
| WeasyPrint | ≥62 | PDF da HTML |
| python-docx | ≥1.0 | DOCX post-processing |
| beautifulsoup4 | ≥4.0 | HTML/tabelle post-processing |
| lxml | ≥5.0 | Parser XML per BeautifulSoup |
| Werkzeug | ≥3.0 | Secure filename, HTTP utilities |
| markdown | ≥3.0 | MD → HTML per anteprime |
| pdfminer.six | ≥2022 | Testo base da PDF |
## 3. Analisi Performance
### Frontend (browser)
| Libreria | Versione | Ruolo |
|---|---|---|
| epub.js | 0.3.93 | Render EPUB |
| pdf.js | 3.x | Render PDF |
| PDF.js | 3.x | Text layer PDF |
| jszip | 3.x | ZIP per EPUB |
- **Conversione**: Pandoc è veloce (ebook < 1 secondo). PDF via WeasyPrint può richiedere qualche secondo.
- **Thread**: Ogni conversione è un thread separato. Per uso singolo non ci sono problemi.
- **SSE**: Connessione keep-alive leggera, ~300 bytes ogni 300ms.
- **Reader**: epub.js rende tutto lato client. File EPUB fino a 50MB senza problemi.
- **Memoria**: L'app in idle usa ~50MB. Durante conversione PDF ~150MB (WeasyPrint).
## 4. Analisi Modularità
## 7. Architettura Componenti
```
bookish/
├── routes/ ⬅️ Separati per dominio (convert vs reader)
│ ├── convert.py
│ └── reader.py
├── services/ ⬅️ Logica di business isolata dal routing
│ ├── converter.py
│ ├── sse_manager.py
│ └── formatter.py
├── templates/ ⬅️ HTML separato per pagina
├── static/ ⬅️ CSS, JS, immagini
│ ├── css/
│ ├── js/
│ └── lib/
┌──────────────────────────────────────────────────┐
│ Flask App │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Convert │ │ Reader │ │ API │ │
│ │ /upload │ │ /reader │ │ /api/* │ │
│ │ /progress│ │ /reader/ │ │ │ │
│ │ /download│ │ <file> │ │ bookmarks│ │
│ └─────┬────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌─────▼─────────────▼─────────────▼──────┐ │
│ │ Services │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │converter │ │ database │─▶ SQLite │ │
│ │ │sse_mgr │ └──────────┘ │ │
│ │ │formatter │ │ │
│ │ └──────────┘ │ │
│ └──────────────────────────────────────────┘ │
│ │
│ Filesystem: uploads/ converted/ bookish.db │
└──────────────────────────────────────────────────┘
```
La separazione è chiara. Unica nota: `converter.py` importa `formatter.py` — dipendenza circolare potenziale ma gestita con import differito.
## 8. Conclusioni
## 5. Possibili Miglioramenti
**Bookish è un'applicazione solida per il suo scopo**: self-hosted, single-user, conversione e lettura ebook.
### Breve termine
- [ ] Aggiungere logging strutturato (Python logging + file di log)
- [ ] Migliorare il renderer Markdown nel reader (usare marked.js via CDN)
- [ ] Aggiungere favicon diversa per stato conversione
- [ ] Test di base con pytest
### Cosa funziona bene
- Il flusso conversione con SSE progress è semplice ma efficace
- Il reader supporta EPUB, PDF e formati testo in un'unica interfaccia
- La persistenza segnalibri con content_hash è robusta: funziona anche su PC diversi
- Il fallback localStorage assicura che il reader non si rompa se il server API è giù
- Slider larghezza e help modal completano l'UX del reader
- La documentazione è completa e in italiano
### Medio termine
- [ ] Supporto per code block syntax highlighting nel reader
- [ ] Drag&drop anche nella pagina reader per caricamento diretto
- [ ] Modalità notte persistente con preferenza sistema (prefers-color-scheme)
- [ ] Aggiungere pipeline di CI/CD per test
### Lungo termine
- [ ] Supporto multi-utente con autenticazione
- [ ] Libreria personale con cronologia conversioni (SQLite)
- [ ] Plugin system per engine di conversione custom
- [ ] Mobile app via PWA
## 6. Conclusioni
Bookish è un'applicazione solida per il suo scopo. L'architettura è pulita, la separazione delle responsabilità è corretta, e le scelte tecnologiche sono appropriate per un progetto self-hostato a uso singolo. Le aree di miglioramento principali sono logging, testing e completezza del reader markdown.
### Cosa sarebbe migliorabile (ma non necessario per single-user)
- Suite di test automatici
- Pipeline CI/CD
- HTTPS nativo (gestito da reverse proxy in produzione)
- Gestione code block più sofisticata nel reader testo
- Mobile optimization
- Logging strutturato (può essere aggiunto con poche righe)
+108 -34
View File
@@ -2,22 +2,23 @@
## Panoramica
Bookish è un'applicazione web Flask monolitica progettata per l'uso self-hostato. Si compone di due macro-funzionalità: un **convertitore di formati ebook** e un **reader web** per visualizzarli.
Bookish è un'applicazione web Flask monolitica progettata per l'uso self-hostato. Si compone di due macro-funzionalità: un **convertitore di formati ebook** e un **reader web** per visualizzarli, con **SQLite** per persistenza di segnalibri e posizioni di lettura.
```
┌──────────┐ ┌─────────────────────────────────────┐
│ Browser │────▶│ Flask │
│ │ │ ┌─────────┐ ┌──────────────────┐ │
│ HTML/CSS │ │ │ Routes │ │ Services │ │
│ JS/ES │ │ │ │ │ │ │
│ │ │ │convert │─▶│converter.py │──▶│ Pandoc
│epub.js │ │ │reader │ │sse_manager.py │ │ WeasyPrint
│pdf.js │ │ │ │ │formatter.py │ │ python-docx
└──────────┘ │ └─────────┘ └──────────────────┘ │
└─────────────────────────────────────┘
│ │
uploads/ converted/
(temporaneo) (temporaneo)
┌──────────┐ ┌──────────────────────────────────────────────┐
│ Browser │────▶│ Flask │
│ │ │ ┌──────────┐ ┌────────────────────────┐ │
│ HTML/CSS │ │ │ Routes │ │ Services │ │
│ JS/ES │ │ │ │ │ │ │
│ │ │ │ convert │─▶│ converter.py │───▶│ Pandoc
│ epub.js │ │ │ reader │ │ sse_manager.py │ │ WeasyPrint
│ pdf.js │ │ │ api │ │ formatter.py │ │ python-docx
└──────────┘ │ └──────────┘ │ database.py ──────────▶│───▶│ SQLite
│ └────────────────────────┘ │
│ │ │ │
└──────────────────────────────────────────────┘
uploads/ converted/
(temporaneo) (temporaneo)
```
## Stack Tecnologico
@@ -25,6 +26,7 @@ Bookish è un'applicazione web Flask monolitica progettata per l'uso self-hostat
| Componente | Tecnologia | Ruolo |
|---|---|---|
| Backend | Flask 3.x + Jinja2 | Server web, routing, template engine |
| Database | SQLite (via sqlite3) | Segnalibri e posizioni di lettura |
| Conversione | Pandoc 3.x (via pypandoc) | Motore di conversione principale |
| PDF avanzato | WeasyPrint | PDF con layout precisi da HTML |
| DOCX avanzato | python-docx | Post-processing documenti Word |
@@ -32,7 +34,7 @@ Bookish è un'applicazione web Flask monolitica progettata per l'uso self-hostat
| Reader EPUB | epub.js 0.3 | Renderer EPUB lato client |
| Reader PDF | pdf.js 3.x | Renderer PDF lato client |
| Progresso | SSE (Server-Sent Events) | Barra progresso real-time |
| Storage | Filesystem locale | `uploads/` e `converted/` |
| Storage | Filesystem + SQLite | `uploads/`, `converted/`, `bookish.db` |
## Flusso Conversione
@@ -58,41 +60,110 @@ Upload file → Validazione formato → Avvio thread conversione
SSE invia download_url
```
## Flusso Reader
## Flusso Reader con Persistenza
```
Upload file → Salva in uploads/ → Redirect a /reader/<file_id>
│
Template reader.html
│
Rileva formato:
├─ EPUB → epub.js
├─ PDF → pdf.js
└─ Testo → HTML renderizzato
│
Interazioni tutte lato client:
- Temi, zoom, ricerca
- Segnalibri, posizione
- Salvataggio in LocalStorage
Upload file → Salva in uploads/ → Calcola SHA256 (content_hash)
│
Redirect a /reader/<file_id>
│
Template reader.html (contiene BOOKISH_HASH)
│
Rileva formato:
├─ EPUB → epub.js
├─ PDF → pdf.js
└─ Testo → HTML renderizzato
│
Interazioni lato client:
- Temi, zoom, ricerca, indice
- Slider larghezza lettura
- Aiuto contestuale (?)
│
Segnalibri e posizione:
├─ Salvataggio immediato in localStorage
├─ Sync asincrono su server SQLite
└─ Caricamento da server con fallback localStorage
```
Il **content_hash** (SHA256 del file) è l'identificatore univoco del libro. Viene calcolato:
- All'upload (restituito nella response)
- All'apertura del reader (dal file su disco)
- Garantisce che lo stesso contenuto → stesso hash → stessi segnalibri
## Architettura del Codice
### Routes (`bookish/routes/`)
- **`convert.py`** — Blueprint `/upload`, `/progress/<task_id>`, `/download/<filename>`, `/formats`
- **`reader.py`** — Blueprint `/reader`, `/reader/<filename>`, `/reader/serve/<filename>`, `/reader/formats`
- **`reader.py`** — Blueprint `/reader`, `/reader/<filename>`, `/reader/serve/<filename>`, `/reader/formats`. Calcola SHA256 del file per identificare univocamente il libro.
- **`api.py`** — Blueprint `/api/bookmarks/*` (CRUD segnalibri), `/api/position/*` (salva/carica posizione lettura)
### Services (`bookish/services/`)
- **`converter.py`** — Dispatcher che sceglie Pandoc o pipeline custom in base alla coppia input/output. Aggiorna SSE progress ad ogni fase.
- **`sse_manager.py`** — Gestisce task in memoria con `{task_id: {progress, status, output_file}}`. Thread-safe con lock.
- **`formatter.py`** — WeasyPrint PDF da HTML con post-processing (tabelle, immagini via BeautifulSoup).
- **`database.py`** — Gestione SQLite con WAL mode. Due tabelle: `bookmarks` (per file) e `reading_positions` (una per file).
### Frontend (`bookish/static/js/`)
- **`main.js`** — Convertitore: drag&drop, form, SSE connection, download
- **`reader.js`** — Reader: epub.js/pdf.js/text viewer, side panel, temi, ricerca, segnalibri, posizione
- **`reader.js`** — Reader completo (800+ righe): epub.js/pdf.js/text viewer, sidebar con TOC/cerca/segnalibri, temi, zoom, slider larghezza, help modal, sync server per bookmarks e posizioni
### Template (`bookish/templates/`)
- **`base.html`** — Layout base con navbar e logo SVG
- **`index.html`** — Convertitore con drag&drop, griglia formati, progress bar
- **`reader.html`** — Reader con toolbar, sidebar, help modal, e script inline per BOOKISH_FILE, BOOKISH_EXT, BOOKISH_HASH
## API REST
| Metodo | Path | Descrizione |
|--------|------|-------------|
| POST | `/upload` | Carica file e avvia conversione |
| GET | `/progress/<task_id>` | SSE stream progresso |
| GET | `/download/<filename>` | Scarica file convertito |
| GET | `/formats?input=<ext>` | Formati disponibili |
| GET | `/reader` | Pagina reader |
| GET | `/reader/<filename>` | Reader per file |
| GET | `/reader/serve/<filename>` | Serve file al reader |
| GET | `/reader/formats` | Formati supportati |
| GET | `/api/bookmarks/<hash>` | Segnalibri del libro |
| POST | `/api/bookmarks` | Aggiunge segnalibro |
| DELETE | `/api/bookmarks/<id>` | Elimina segnalibro |
| GET | `/api/position/<hash>` | Posizione di lettura |
| PUT | `/api/position/<hash>` | Salva posizione di lettura |
## Database SQLite (`bookish.db`)
### Tabella `bookmarks`
| Colonna | Tipo | Descrizione |
|---------|------|-------------|
| id | TEXT PK | ID univoco del segnalibro |
| content_hash | TEXT | SHA256 del file libro |
| type | TEXT | epub, pdf, text |
| cfi | TEXT | CFI per EPUB |
| href | TEXT | Href del capitolo EPUB |
| page | INTEGER | Numero pagina PDF |
| total_pages | INTEGER | Pagine totali (PDF) |
| scroll_pct | INTEGER | % scorrimento (testo) |
| label | TEXT | Etichetta visualizzata |
| chapter_title | TEXT | Titolo capitolo corrente |
| created | REAL | Timestamp creazione |
### Tabella `reading_positions`
| Colonna | Tipo | Descrizione |
|---------|------|-------------|
| content_hash | TEXT PK | SHA256 del file libro |
| type | TEXT | epub, pdf, text |
| cfi | TEXT | CFI per EPUB |
| href | TEXT | Href del capitolo |
| page | INTEGER | Pagina PDF |
| scroll_pct | INTEGER | % scorrimento (testo) |
| chapter_title | TEXT | Titolo capitolo |
| updated | REAL | Timestamp ultimo aggiornamento |
## Decisioni Architetturali
@@ -100,8 +171,11 @@ Upload file → Salva in uploads/ → Redirect a /reader/<file_id>
|---|---|
| Thread invece di Celery | Uso singolo utente, niente Redis, minore complessità |
| SSE invece di WebSocket | Sincrono semplice, nessuna dipendenza extra, supporto nativo |
| LocalStorage per reader | Zero backend, nessun DB necessario per lettura |
| File temporanei con cleanup | Nessun database, i file si auto-puliscono dopo 1h |
| content_hash (SHA256) invece di UUID | Identifica il contenuto, non l'istanza. Stesso file = stesso hash |
| SQLite per persistenza | Incluso in Python, zero configurazione, file singolo |
| Server + localStorage come fallback | Offline-resilient, UX istantanea, sync asincrono |
| Position save debounced (1.5s) | Evita flooding di scritture SQLite ad ogni pagina |
| File temporanei con cleanup | Nessun accumulo, auto-pulizia dopo 1h |
| JS vanilla | Nessun framework, leggero, manutenibile |
| Pandoc via pypandoc-binary | Include Pandoc binary, nessuna installazione systema richiesta |
@@ -111,4 +185,4 @@ Upload file → Salva in uploads/ → Redirect a /reader/<file_id>
- **No autenticazione**: Uso personale, nessun multi-utente
- **No HTTPS di base**: Da abilitare con reverse proxy (nginx/caddy)
- **No ottimizzazione mobile**: Funziona ma non è prioritario
- **estione code block reader**: Reader testo ha markdown renderer minimale
- **Gestione code block reader**: Reader testo ha markdown renderer minimale
+126 -57
View File
@@ -1,81 +1,105 @@
# Deploy Bookish
# Deploy di Bookish
## Su Proxmox LXC (raccomandato)
### 1. Crea container LXC
```bash
pct create 120 local:vault/almalinux-9-default_20240918_amd64.tar.xz \
--storage local-lvm \
--memory 1024 \
--swap 512 \
--cores 2 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--ostype almalinux \
--unprivileged 1
pct start 120
pct enter 120
```
### 2. Installa dipendenze
```bash
# Python e strumenti di sviluppo
dnf install -y python3 python3-pip git python3-devel gcc \
pango-devel cairo-devel gdk-pixbuf2-devel
# Per WeasyPrint
dnf install -y libffi-devel redhat-rpm-config
```
### 3. Clona e setup
## Preparazione
```bash
# Clona il repository
git clone http://192.168.0.183:8085/truetype/bookish.git
cd bookish
# Ambiente virtuale
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Verifica
python app.py
# → Avvia su 0.0.0.0:5000 (o porta libera successiva)
# → Crea automaticamente bookish.db
```
## Opzioni di Deploy
### 1. Proxmox LXC (consigliato)
Crea un container Linux privilegiato (Debian/Ubuntu):
```bash
pct create 100 local/vault/debian-12-standard_12.7-1_amd64.tar.zst \
--hostname bookish \
--storage local-zfs \
--rootfs 4 \
--cores 1 \
--memory 512 \
--net0 name=eth0,bridge=vmbr0,firewall=1,ip=dhcp
```
All'interno del container:
```bash
apt update && apt install -y python3 python3-venv python3-pip git
git clone http://192.168.0.183:8085/truetype/bookish.git /opt/bookish
cd /opt/bookish
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
### 4. Crea service systemd
### 2. Docker
```dockerfile
FROM python:3.12-slim
RUN apt-get update && apt-get install -y \
libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 \
libffi-dev shared-mime-info
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN mkdir -p uploads converted
EXPOSE 5000
CMD ["python", "app.py"]
```
Build e avvio:
```bash
docker build -t bookish .
docker run -d \
--name bookish \
-p 5000:5000 \
-v bookish_data:/app/uploads \
-v bookish_data:/app/converted \
-v bookish_db:/app \
--restart unless-stopped \
bookish
```
### 3. Systemd Service
```ini
# /etc/systemd/system/bookish.service
[Unit]
Description=Bookish Ebook Converter & Reader
Description=Bookish Flask App
After=network.target
[Service]
Type=simple
User=root
User=bookish
WorkingDirectory=/opt/bookish
ExecStart=/opt/bookish/.venv/bin/python /opt/bookish/app.py 5000
Environment=PATH=/opt/bookish/.venv/bin
Environment=BOOKISH_SECRET=your-secure-secret-key
ExecStart=/opt/bookish/.venv/bin/python app.py
Restart=always
RestartSec=5
Environment=BOOKISH_SECRET=your-secret-here
Environment=BOOKISH_DEBUG=false
RestartSec=10
[Install]
WantedBy=multi-user.target
```
```bash
systemctl daemon-reload
systemctl enable --now bookish
```
## Docker (alternativa)
```dockerfile
FROM python:3.11-slim
RUN apt-get update && apt-get install -y pandoc libpango-1.0-0 \
libcairo2 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 5000
CMD ["python", "app.py", "5000"]
sudo systemctl daemon-reload
sudo systemctl enable bookish
sudo systemctl start bookish
```
## Reverse Proxy (Caddy)
@@ -86,10 +110,55 @@ bookish.tuodominio.it {
}
```
Con Caddy l'HTTPS è automatico.
Con Caddy ottieni automaticamente HTTPS tramite Let's Encrypt.
## Pulizia e Manutenzione
## Dati persistenti
I file in `uploads/` e `converted/` vengono puliti automaticamente dopo 1 ora. Nessun DB da manutenere.
Bookish usa il filesystem per dati temporanei e un database SQLite per dati permanenti:
Per backup basta copiare la directory del progetto (escludendo `uploads/`, `converted/`, `.venv/`).
| Cosa | Dove | Persistente? |
|---|---|---|
| File caricati | `uploads/` | ❌ (pulizia 1h) |
| File convertiti | `converted/` | ❌ (pulizia 1h) |
| Segnalibri e posizioni | `bookish.db` | ✅ (SQLite) |
**Backup**: per salvare segnalibri e posizioni, copia `bookish.db`:
```bash
cp /opt/bookish/bookish.db /tuo/backup/
```
Il database si ricrea automaticamente se manca (perdendo però i dati precedenti).
## Configurazione Porta
Se `app.py` non trova la porta specificata, scorre in sequenza (`+1`) finché non trova una porta libera. Puoi specificare la porta di partenza come argomento:
```bash
python app.py 8080
# Prova 8080, 8081, 8082...
```
## Variabili d'ambiente
| Variabile | Default | Descrizione |
|---|---|---|
| `BOOKISH_SECRET` | `bookish-secret-key-change-in-production` | Flask secret key |
| `BOOKISH_PORT` | 5000 | Porta di partenza per la ricerca |
| `FLASK_DEBUG` | 0 | Modalità debug (1 per attivare) |
## Manutenzione
```bash
# Update app
git pull
source .venv/bin/activate
pip install -r requirements.txt --upgrade
systemctl restart bookish # se systemd
# Pulizia hard disk
rm -rf uploads/* converted/*
# Backup
cp bookish.db bookish.db.$(date +%Y%m%d).bak
```
+63 -13
View File
@@ -25,20 +25,54 @@
| FB2 | EPUB, MD, DOCX, PDF, TXT, HTML, LaTeX |
| LaTeX | EPUB, MD, DOCX, PDF, TXT, HTML |
### Reader
### Reader — Operazioni base
1. Vai su **Reader** nella navigazione
2. Carica un ebook (EPUB, PDF, MD, TXT, HTML, FB2, DOCX)
2. Trascina un ebook (EPUB, PDF, MD, TXT, HTML, FB2, DOCX) o clicca per caricarlo
3. Usa la toolbar per:
- **☰** — Apri/chiudi indice
- **A− / A+** — Zoom font
- **☀️ / 🌙 / 🟤** — Cambia tema (chiaro/scuro/seppia)
- **🔍** — Cerca nel testo
- **⛶** — Schermo intero
4. Naviga con frecce tastiera ← → o cliccando ai lati
5. La posizione di lettura viene salvata automaticamente
### API Endpoints
| Pulsante | Azione |
|---|---|
| **☰** | Apri/chiudi indice laterale |
| **⇔** | Slider larghezza area di lettura (40–100%) |
| **A− / A+** | Zoom font |
| **☀️ / 🌙 / 🟤** | Cambia tema (chiaro/scuro/seppia) |
| **🔍** | Cerca nel testo |
| **🔖** | Aggiungi segnalibro alla posizione corrente |
| **⛶** | Schermo intero |
| **?** | Aiuto e scorciatoie da tastiera |
4. Naviga con le frecce **← →** della tastiera
5. La **posizione di lettura** viene salvata automaticamente (locale + server)
### Reader — Segnalibri
- Premi **🔖** nella toolbar o **Ctrl+B** / **⌘B** per aggiungere un segnalibro
- Un toast di conferma appare in basso e il pulsante fa un piccolo "pulse"
- Vai nella sidebar **☰ → Segnalibri** per vedere l'elenco
- **Clicca** su un segnalibro per tornarci
- Premi **✕** per eliminarlo
- I segnalibri sono salvati su server SQLite + localStorage (fallback)
- Lo stesso libro ha sempre gli stessi segnalibri, anche su PC diverso
### Reader — Scorciatoie da tastiera
| Tasti | Azione |
|---|---|
| **←** / **→** | Pagina precedente/successiva |
| **Ctrl+B** / **⌘B** | Aggiungi segnalibro |
| **Ctrl+F** / **⌘F** | Cerca nel libro |
| **+** / **-** | Zoom avanti/indietro |
| **F** | Schermo intero |
| **Esc** | Chiudi help modal / Esci da fullscreen |
### Reader — Slider larghezza
La barra a destra nella toolbar (con icona ⇔) regola la larghezza dell'area di lettura dal 40% al 100% dello schermo. Utile per file con righe molto lunghe o per preferenze personali di lettura. L'impostazione viene salvata in localStorage.
## API Endpoints
### Endpoints pubblici
| Metodo | Path | Descrizione |
|---|---|---|
@@ -51,16 +85,32 @@
| GET | `/reader/serve/<filename>` | Serve il file al reader |
| GET | `/reader/formats` | Formati supportati dal reader |
### API REST (bookmarks e posizioni)
| Metodo | Path | Descrizione |
|---|---|---|
| GET | `/api/bookmarks/<content_hash>` | Recupera tutti i segnalibri del libro |
| POST | `/api/bookmarks` | Aggiunge un segnalibro |
| DELETE | `/api/bookmarks/<id>` | Elimina un segnalibro |
| GET | `/api/position/<content_hash>` | Recupera l'ultima posizione di lettura |
| PUT | `/api/position/<content_hash>` | Salva la posizione di lettura (body JSON) |
## Domande frequenti
**D: Che qualità ha la conversione?**
R: Pandoc preserva titoli, grassetto/corsivo, elenchi, tabelle semplici e immagini. Per layout complessi (es. PDF con colonne multiple) la fedeltà dipende dalla complessità del file originale.
**D: I file vengono conservati?**
R: No, vengono cancellati dopo 1 ora. Usa il download subito dopo la conversione.
R: I file in `uploads/` e `converted/` vengono cancellati dopo 1 ora. Usa il download subito dopo la conversione. I segnalibri e le posizioni di lettura sono invece permanenti in `bookish.db`.
**D: I segnalibri restano se ricarico lo stesso libro?**
R: Sì. I segnalibri sono legati al contenuto del file (SHA256), non al nome o all'UUID di upload. Stesso file = stessi segnalibri.
**D: Posso usare i segnalibri da un altro PC?**
R: Sì, se sei sulla stessa LAN e raggiungi lo stesso server. I segnalibri sono salvati su SQLite, non nel browser.
**D: Quanto spazio serve?**
R: Minimo. L'app stessa è ~5MB. Pandoc binary incluso ~35MB extra.
R: Minimo. L'app stessa è ~5MB. Pandoc binary incluso ~35MB extra. Il database SQLite occupa pochi KB.
**D: Posso usarlo su mobile?**
R: Il convertitore è responsive. Il reader funziona ma non è ottimizzato per schermi piccoli.
@@ -75,4 +125,4 @@ R: Imposta `BOOKISH_SECRET` come variabile d'ambiente prima di avviare.
- Path traversal prevenuto con `os.path.basename()` e `secure_filename()`
- MIME types controllati al download
- Limite file a 50MB
- Pulizia automatica file temporanei
- Pulizia automatica file temporanei dopo 1h