diora-web/docs/library.md

84 lines
4.4 KiB
Markdown
Raw Normal View History

Bibliothek neu: Ordner als Filter-Chips überall, Cover-Raster, Cover verschlüsselt und generiert (noch nicht veröffentlicht) - Ordner wie Tags (docs/library.md): folders.js zeichnet die Chip-Reihe, das Blatt „In Ordner …“ (Häkchen, Neuer Ordner) und „Ordner verwalten“ (umbenennen = zusammenlegen, löschen, Reihenfolge). E-Books: `folders` im verschlüsselten Meta, Reihenfolge in verschlüsselten Bibliotheks-Einstellungen (/books/prefs/). Podcasts/Hörbücher: PodcastFeed.folders (Migration 0021, übernimmt `folder`), /podcasts/folders/ (+rename, +delete). Blogs: Reihenfolge (/feeds/folders/order/). - Bibliothek (53-library.js): Kopf mit Suche, Sortierung, Raster/Liste und +; Chips Angefangen · Ungelesen · Gelesen · Ordner; eine „Weiterlesen“-Karte; Mehrfachauswahl (lange drücken). E-Ink und diora Reader beginnen als Liste. - Cover Ende-zu-Ende verschlüsselt (covers.js, /books/<id>/cover/): aus dem E-Book (EPUB-Coverbild, PDF Seite 1), 300 px, mit dem Nutzerschlüssel verschlüsselt, einmal hochgeladen; sparsam im Leerlauf, nie beim Lesen, nie auf E-Ink. - Bücher ohne Cover bekommen eins (gencover.js): Stichwörter aus Titel, Autor, Regal und Ordnern wählen ein Gestaltungskonzept (Konstruktivismus, Geometrie, Psyche, Wellen, Karte, Kosmos, Ornament, Botanik, Berge, Zellen, Raster, Schatten, Typo, sonst Bauhaus); ein Hash aus Titel und Autor Palette, Aufbau und Details – einzigartig, überall gleich, nichts gespeichert. - Hörbücher: Ordner-Chips statt Kacheln, „In Ordner …“ mit mehreren Ordnern. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:44:23 +02:00
# Folders and the library (redesign)
## Folders everywhere: tags shown as filter chips
One idea of a folder for every area — Bücher, Zeitschriften, Hörbücher,
Podcasts, Blogs (and the news' Ressorts, which already work this way):
- A thing can be in **several folders** (they work like tags); none is fine.
- Folders are **filters**, not rooms: a row of chips on top —
`Alle · <folder> n · … · Ohne Ordner` — tapping one filters in place; no
"inside a folder" view, no back button. On a wide window the row wraps.
- **Assigning**: mark one or more things (long press / ☐ select mode, or ⋮ on
one), then "In Ordner …": a sheet with every folder of the area as checkboxes
and "Neuer Ordner". No typing a name that must match.
- **Managing** (⋮ on the chip row → "Ordner verwalten"): rename, merge (rename
onto an existing name), delete (the things stay, only the folder goes),
reorder by dragging. The order is the chip order.
- **Automatic groups** stay automatic and look different from folders (no
chip; a stack/group heading): audiobook series, magazine periodicals.
### Where folders are kept
| Area | Field | Notes |
|------|-------|-------|
| E-books, magazines | encrypted meta `folders: [names]` | `folder` (the first) kept for older clients; read `folders` or else `[folder]` |
| Audiobooks, podcasts | `PodcastFeed.folders` (JSON list) | feed setting `folders`; `folder` (string) still accepted |
| Blogs | `Source.folders` (exists) | |
| News | `Source.category` (one Ressort) | already chips in Nachrichten |
The folder order per area: e-books in the encrypted user settings blob (names
are private), the others on the server (`/podcasts/folders/`, `/feeds/folders/`,
`{order: [names]}`).
### Shared code: `static/js/folders.js` (diora-web, every platform)
```
DioraFolders.chips(el, {folders: [{name, count}], active, none: count|0, onPick(name|''|null), onManage()})
DioraFolders.assign({title, folders: [names], selected: [names], onDone(names)}) // the sheet
DioraFolders.manage({folders: [names], onRename(old, new), onDelete(name), onOrder(names)})
```
Each area keeps its own storage and calls these for the look and the dialogs.
## The library (Bücher, Zeitschriften)
- **Header**: title, search (title, author), sort (zuletzt gelesen · Titel ·
Autor · hinzugefügt), ⊞/☰ grid or list, `+` (Buch hinzufügen, Aus Cloud).
- **Filter chips**: Alle · Angefangen · Ungelesen · Gelesen — then the folders.
- **Weiterlesen**: one card on top (cover, title, "Seite 132 von 186 · gestern",
▶), not repeated in the list below.
- **Grid** (default on phone and desktop): covers with a progress line, title.
**List** (default on e-ink / diora Reader): one row per book, small cover,
title, author, % / ✓.
### Covers, end-to-end encrypted
A client that has a book's file extracts its cover (EPUB: the OPF cover image;
PDF: page 1), scales it to 240 px wide JPEG, **encrypts it with the user's key**
(AES-GCM like the meta) and uploads it once: `POST /books/<id>/cover/
{cover_ct, cover_iv}`. `GET /books/` lists `has_cover`; `GET /books/<id>/cover/`
returns `{cover_ct, cover_iv}`. Clients cache the decrypted image locally. The
server never sees a cover.
### Generated covers
A book without a cover (or one set to `cover: 'generated'` in its meta) gets one
drawn by `static/js/gencover.js`: an SVG, the same on every device, never stored.
A **concept** (motif, palettes, typeface) is chosen by score:
- words in the title (3), the shelf category (2) and the author (2, only at a
name's start). A stem of five letters or more counts anywhere (German
compounds), a shorter one at a word's start, one of three letters as a whole
word; `^` / `$` in the list force a word's start / end.
- the folders, by name (`FOLDER_THEMES`): the first counts 2.5 — more than an
author or shelf word, less than a title word — further ones 1.
Concepts: konstruktiv (Marx), geometrie (Philosophie: rings, turning squares,
triangle/circle/square), psyche (Psychoanalyse: two ellipses, the Borromean
knot, a spiral), karte (Geschichte), kosmos (Science-Fiction), ornament
(Fantasy), raster (Politik, Soziologie), schatten (Krimi: a red line, a lit
doorway), grusel (Horror), klassiker (patterned paper with a title plate),
sakral (Religion & Mythologie), spiel (Kinder & Jugend), code (Informatik),
typo, wellen, botanik, berge, zellen — and bauhaus when nothing matches. A hash
of title and author picks palette, layout and every detail.