retold-remote 0.0.22 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/retold-remote.css +87 -20
- package/docs/README.md +59 -11
- package/docs/_sidebar.md +1 -0
- package/docs/collections.md +30 -0
- package/docs/ebook-reader.md +75 -1
- package/docs/image-explorer.md +27 -1
- package/docs/server-setup.md +28 -18
- package/docs/stack-launcher.md +218 -0
- package/docs/ultravisor-integration.md +2 -0
- package/package.json +10 -7
- package/source/Pict-Application-RetoldRemote.js +2 -0
- package/source/RetoldRemote-ExtensionMaps.js +1 -1
- package/source/cli/RetoldRemote-Server-Setup.js +240 -2
- package/source/cli/RetoldRemote-Stack-Launcher.js +387 -0
- package/source/cli/RetoldRemote-Stack-Run.js +41 -0
- package/source/cli/commands/RetoldRemote-Command-Serve.js +129 -54
- package/source/providers/CollectionManager-AddItems.js +166 -0
- package/source/providers/Pict-Provider-GalleryNavigation.js +46 -0
- package/source/providers/keyboard-handlers/KeyHandler-ImageExplorer.js +5 -0
- package/source/providers/keyboard-handlers/KeyHandler-Viewer.js +23 -0
- package/source/server/RetoldRemote-CollectionExportService.js +696 -0
- package/source/server/RetoldRemote-CollectionService.js +5 -0
- package/source/server/RetoldRemote-EbookService.js +194 -3
- package/source/server/RetoldRemote-SubimageService.js +530 -0
- package/source/server/RetoldRemote-ToolDetector.js +50 -0
- package/source/server/RetoldRemote-UltravisorOperations.js +6 -6
- package/source/views/MediaViewer-EbookViewer.js +419 -1
- package/source/views/MediaViewer-PdfViewer.js +963 -0
- package/source/views/PictView-Remote-CollectionsPanel.js +166 -0
- package/source/views/PictView-Remote-ImageExplorer.js +606 -1
- package/source/views/PictView-Remote-ImageViewer.js +2 -2
- package/source/views/PictView-Remote-Layout.js +12 -0
- package/source/views/PictView-Remote-MediaViewer.js +83 -25
- package/source/views/PictView-Remote-SubimagesPanel.js +353 -0
- package/web-application/css/retold-remote.css +87 -20
- package/web-application/docs/README.md +59 -11
- package/web-application/docs/_sidebar.md +1 -0
- package/web-application/docs/collections.md +30 -0
- package/web-application/docs/ebook-reader.md +75 -1
- package/web-application/docs/image-explorer.md +27 -1
- package/web-application/docs/server-setup.md +28 -18
- package/web-application/docs/stack-launcher.md +218 -0
- package/web-application/docs/ultravisor-integration.md +2 -0
- package/web-application/retold-remote.js +399 -45
- package/web-application/retold-remote.js.map +1 -1
- package/web-application/retold-remote.min.js +13 -12
- package/web-application/retold-remote.min.js.map +1 -1
|
@@ -4,10 +4,18 @@ A browser-based media server and NAS file explorer. Point it at a folder and bro
|
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
|
+
Just the media browser:
|
|
8
|
+
|
|
7
9
|
```bash
|
|
8
10
|
npx retold-remote serve /path/to/media
|
|
9
11
|
```
|
|
10
12
|
|
|
13
|
+
The full stack (Retold Remote + embedded Orator-Conversion + child Ultravisor):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
retold-stack /path/to/media
|
|
17
|
+
```
|
|
18
|
+
|
|
11
19
|
Or with Docker:
|
|
12
20
|
|
|
13
21
|
```bash
|
|
@@ -17,17 +25,24 @@ docker run -p 8086:8086 -v /path/to/media:/media retold-remote
|
|
|
17
25
|
|
|
18
26
|
Then open `http://localhost:8086` in a browser.
|
|
19
27
|
|
|
28
|
+
See [Stack Launcher](stack-launcher.md) for what `retold-stack` does and how the XDG-style data paths work.
|
|
29
|
+
|
|
20
30
|
## Features
|
|
21
31
|
|
|
22
32
|
- **Gallery browser** with grid and list views, thumbnail generation, and lazy loading
|
|
23
33
|
- **Image viewer** with three fit modes, 0.25x-8x zoom, and EXIF orientation support
|
|
24
34
|
- **Video viewer** with action menu, in-browser playback, VLC streaming, and frame explorer
|
|
25
35
|
- **Audio viewer** with waveform visualization, selection-based playback, and segment extraction
|
|
26
|
-
- **eBook reader** for EPUB and MOBI with table of contents and
|
|
36
|
+
- **eBook reader** for EPUB and MOBI with table of contents, page navigation, text selection capture, and visual region selection
|
|
37
|
+
- **PDF viewer** with full pdf.js rendering, page navigation, text layer selection, and visual region selection
|
|
38
|
+
- **Document conversion** for DOC, DOCX, RTF, ODT, WPD, ODP, PPT(X), ODS, XLS(X) — converted to PDF on the fly via Orator-Conversion + LibreOffice
|
|
27
39
|
- **Code/text viewer** with syntax highlighting for 30+ languages
|
|
28
|
-
- **PDF viewer** via native browser rendering
|
|
29
40
|
- **Archive browsing** into zip, 7z, rar, tar.gz, cbz, and cbr files as virtual folders
|
|
30
41
|
- **Filtering and sorting** by media type, extension, file size, date, and text search (with regex)
|
|
42
|
+
- **Subimage regions** — draw labeled rectangles on images, ebook pages, and PDF pages; persisted per file
|
|
43
|
+
- **Collections & Export** — bookmark files, image crops, video clips, audio clips, and document regions; export the whole collection to a folder with proper file cutting
|
|
44
|
+
- **Stack mode** — single command launches Ultravisor coordinator + Retold Remote + embedded Orator-Conversion with sane XDG data paths
|
|
45
|
+
- **Ultravisor offload** — heavy work (frame extraction, waveforms, conversions) dispatched to a beacon worker on a faster machine
|
|
31
46
|
- **15 themes** from greyscale to retro and cyberpunk
|
|
32
47
|
- **Full keyboard navigation** across every mode
|
|
33
48
|
- **Media type override** to force any file open as image, video, audio, or text (keys 1-4)
|
|
@@ -40,14 +55,16 @@ Then open `http://localhost:8086` in a browser.
|
|
|
40
55
|
| Document | Contents |
|
|
41
56
|
|----------|----------|
|
|
42
57
|
| [Server Setup and Docker](server-setup.md) | Installation, CLI options, environment variables, configuration, Docker |
|
|
58
|
+
| [Stack Launcher](stack-launcher.md) | `retold-stack` and `--stack` flag, XDG paths, child process orchestration |
|
|
59
|
+
| [Ultravisor Integration](ultravisor-integration.md) | Offloading heavy media processing to a beacon worker |
|
|
43
60
|
| [Image Viewer](image-viewer.md) | Fit modes, zoom, keyboard shortcuts, mouse interactions |
|
|
44
61
|
| [Video Viewer](video-viewer.md) | Action menu, in-browser playback, VLC streaming |
|
|
45
62
|
| [Audio Viewer](audio-viewer.md) | HTML5 playback, autoplay, VLC streaming |
|
|
46
|
-
| [eBook Reader](ebook-reader.md) | EPUB/MOBI support,
|
|
47
|
-
| [Image Explorer](image-explorer.md) | Deep-zoom with OpenSeadragon, DZI tiling,
|
|
63
|
+
| [eBook Reader](ebook-reader.md) | EPUB/MOBI support, TOC, page nav, text/region selection |
|
|
64
|
+
| [Image Explorer](image-explorer.md) | Deep-zoom with OpenSeadragon, DZI tiling, region selection |
|
|
48
65
|
| [Video Explorer](video-explorer.md) | Frame grid, timeline, range selection, clip extraction |
|
|
49
66
|
| [Audio Explorer](audio-explorer.md) | Waveform visualization, selection, zoom, segment playback |
|
|
50
|
-
| [Collections](collections.md) | Bookmarks, favorites, quick-add, item types, operation plans |
|
|
67
|
+
| [Collections](collections.md) | Bookmarks, favorites, quick-add, item types, operation plans, export |
|
|
51
68
|
| [File Metadata](metadata.md) | Info overlay, sidebar metadata, EXIF/GPS, ffprobe, explorer info bars |
|
|
52
69
|
|
|
53
70
|
## Keyboard Shortcuts (All Modes)
|
|
@@ -158,11 +175,24 @@ In the frame preview overlay:
|
|
|
158
175
|
| `+` / `=` | Zoom in |
|
|
159
176
|
| `-` | Zoom out |
|
|
160
177
|
| `0` | Reset zoom |
|
|
161
|
-
| `
|
|
178
|
+
| `s` | Toggle region selection mode (draw rectangles) |
|
|
179
|
+
| `a` | Quick-add to collection (current region if selected) |
|
|
162
180
|
| `b` | Toggle collection panel |
|
|
163
181
|
| `h` | Toggle favorite |
|
|
164
182
|
| `Esc` | Back to viewer |
|
|
165
183
|
|
|
184
|
+
### Document Viewer (PDF / EPUB)
|
|
185
|
+
|
|
186
|
+
| Key | Action |
|
|
187
|
+
|-----|--------|
|
|
188
|
+
| `s` | Toggle visual region selection mode |
|
|
189
|
+
| `a` | Quick-add document region to collection |
|
|
190
|
+
| `Esc` | Back to gallery |
|
|
191
|
+
|
|
192
|
+
In the PDF viewer, page navigation buttons and a page input are in the controls bar. The text layer supports native browser text selection — use the **Save Selection** button to capture selected text as a labeled region.
|
|
193
|
+
|
|
194
|
+
In the EPUB reader, the controls bar exposes **Save Selection** (captures the selected text + CFI) and **Select Region** (draws a rectangle over the rendered page).
|
|
195
|
+
|
|
166
196
|
### Sidebar (F9)
|
|
167
197
|
|
|
168
198
|
| Key | Action |
|
|
@@ -184,7 +214,9 @@ mp4, webm, mov, mkv, avi, wmv, flv, m4v, ogv, mpg, mpeg, mpe, mpv, m2v, ts, mts,
|
|
|
184
214
|
mp3, wav, ogg, flac, aac, m4a, wma, oga
|
|
185
215
|
|
|
186
216
|
### Documents
|
|
187
|
-
pdf, epub, mobi
|
|
217
|
+
pdf, epub, mobi, doc, docx, rtf, odt, wpd, wps, pages, odp, ppt, pptx, ods, xls, xlsx
|
|
218
|
+
|
|
219
|
+
Documents beyond pdf/epub/mobi are converted to PDF on the fly via the embedded Orator-Conversion service (requires LibreOffice or Calibre on the server).
|
|
188
220
|
|
|
189
221
|
### Archives
|
|
190
222
|
zip, 7z, rar, tar, tar.gz, tar.bz2, tar.xz, tgz, cbz, cbr
|
|
@@ -204,13 +236,16 @@ These external tools enhance functionality when available on the server:
|
|
|
204
236
|
|
|
205
237
|
| Tool | Feature |
|
|
206
238
|
|------|---------|
|
|
207
|
-
| **sharp** (npm) | Fast image thumbnail generation |
|
|
239
|
+
| **sharp** (npm) | Fast image thumbnail generation, region cropping |
|
|
208
240
|
| **ImageMagick** | Fallback image thumbnails |
|
|
209
|
-
| **ffmpeg** | Video thumbnails, frame extraction, audio waveforms |
|
|
241
|
+
| **ffmpeg** | Video thumbnails, frame extraction, audio waveforms, clip cutting |
|
|
210
242
|
| **ffprobe** | Media metadata (duration, resolution, codec) |
|
|
211
243
|
| **7-Zip** (7z) | Archive browsing for rar, 7z, tar.* formats |
|
|
212
244
|
| **VLC** | External video streaming |
|
|
213
|
-
| **
|
|
245
|
+
| **audiowaveform** (BBC) | Faster audio waveform peak generation |
|
|
246
|
+
| **ebook-convert** (Calibre) | MOBI/AZW to EPUB conversion (and PDF fallback for documents) |
|
|
247
|
+
| **LibreOffice** (`soffice`) | DOC/DOCX/RTF/ODT/WPD/PPT(X)/XLS(X) to PDF conversion |
|
|
248
|
+
| **pdftk** + **pdftoppm** (poppler) | PDF page extraction and rendering (used by Orator-Conversion) |
|
|
214
249
|
|
|
215
250
|
Without these tools the application still works -- images serve directly, videos play in-browser, and zip/cbz archives use native extraction.
|
|
216
251
|
|
|
@@ -231,7 +266,20 @@ Without these tools the application still works -- images serve directly, videos
|
|
|
231
266
|
| GET | `/api/media/audio-waveform?path=&peaks=` | Audio waveform peak data |
|
|
232
267
|
| GET | `/api/media/audio-segment?path=&start=&end=` | Extract audio segment |
|
|
233
268
|
| GET | `/api/media/ebook-convert?path=` | Convert MOBI to EPUB |
|
|
234
|
-
| GET | `/api/media/
|
|
269
|
+
| GET | `/api/media/doc-convert?path=` | Convert DOC/DOCX/RTF/ODT/WPD/etc. to PDF |
|
|
270
|
+
| GET | `/api/media/ebook/:cacheKey/:filename` | Serve converted ebook or PDF |
|
|
271
|
+
| GET | `/api/media/pdf-text?path=&page=` | Extract text from a PDF page |
|
|
272
|
+
| GET | `/api/media/subimage-regions?path=` | List labeled regions for an image, ebook, or PDF |
|
|
273
|
+
| POST | `/api/media/subimage-regions` | Add a labeled region (visual or text-selection) |
|
|
274
|
+
| PUT | `/api/media/subimage-regions/:id` | Update a region's label or coordinates |
|
|
275
|
+
| DELETE | `/api/media/subimage-regions/:id?path=` | Remove a labeled region |
|
|
276
|
+
| GET | `/api/collections` | List all collections |
|
|
277
|
+
| POST | `/api/collections/:guid/items` | Add items to a collection |
|
|
278
|
+
| POST | `/api/collections/:guid/export` | Export collection to a folder (cuts clips, crops images) |
|
|
279
|
+
| POST | `/api/conversion/1.0/doc-to-pdf` | Convert any document buffer to PDF (via Orator-Conversion) |
|
|
280
|
+
| POST | `/api/conversion/1.0/pdf-to-page-png/:Page` | Render a PDF page as PNG |
|
|
281
|
+
| POST | `/api/conversion/1.0/pdf-to-page-jpg/:Page/:LongSidePixels` | Render and resize a PDF page as JPEG |
|
|
282
|
+
| POST | `/api/conversion/1.0/image/resize` | Resize an image |
|
|
235
283
|
| POST | `/api/media/open` | Open file in external player (VLC) |
|
|
236
284
|
|
|
237
285
|
## License
|
|
@@ -16,6 +16,11 @@ Press `a` in any mode to add the current item to a collection. If a collection i
|
|
|
16
16
|
| Video explorer | Video frame | Path, timestamp, cached frame image |
|
|
17
17
|
| Video explorer (with selection) | Video clip | Path, start time, end time |
|
|
18
18
|
| Audio explorer (with selection) | Audio clip | Path, start time, end time |
|
|
19
|
+
| Image explorer (with active region) | Image crop | Path, X, Y, Width, Height in original pixels |
|
|
20
|
+
| PDF viewer (with text selection) | Document region (text) | Path, page number, selected text |
|
|
21
|
+
| PDF viewer (with visual region) | Document region (visual) | Path, page number, X/Y/Width/Height in PDF units |
|
|
22
|
+
| EPUB reader (with text selection) | Document region (text) | Path, CFI, spine index, chapter title, selected text |
|
|
23
|
+
| EPUB reader (with visual region) | Document region (visual) | Path, X/Y/Width/Height in container coordinates |
|
|
19
24
|
|
|
20
25
|
### Folder Choice
|
|
21
26
|
|
|
@@ -136,11 +141,35 @@ Pending item destinations can be edited inline by clicking the destination path.
|
|
|
136
141
|
| `a` | Gallery, viewer, all explorers | Quick-add current item to collection |
|
|
137
142
|
| `s` | Video explorer | Add selected range as video clip |
|
|
138
143
|
| `s` | Audio explorer | Save audio snippet to collection |
|
|
144
|
+
| `s` | Image explorer | Toggle region selection mode |
|
|
145
|
+
| `s` | Document viewer (PDF/EPUB) | Toggle visual region selection mode |
|
|
139
146
|
| `[` | Video explorer | Set selection start at current frame |
|
|
140
147
|
| `]` | Video explorer | Set selection end at current frame |
|
|
141
148
|
| `b` | All modes | Toggle collection panel |
|
|
142
149
|
| `h` | All modes | Toggle favorite |
|
|
143
150
|
|
|
151
|
+
## Export
|
|
152
|
+
|
|
153
|
+
Collections can be exported to a folder within the content root. Each item is processed according to its type:
|
|
154
|
+
|
|
155
|
+
| Item Type | Export Behavior |
|
|
156
|
+
|-----------|----------------|
|
|
157
|
+
| `file` / `subfile` | Copied directly to the destination |
|
|
158
|
+
| `image-crop` | Cropped via sharp at the original resolution |
|
|
159
|
+
| `video-clip` | Extracted via `ffmpeg -ss -t -c copy` |
|
|
160
|
+
| `video-frame` | Extracted via `ffmpeg -ss -vframes 1` |
|
|
161
|
+
| `audio-clip` | Extracted via `ffmpeg -ss -t -vn` |
|
|
162
|
+
| `document-region` (text) | Written as a `.txt` file with the captured text and source metadata |
|
|
163
|
+
| `document-region` (visual) | Metadata file describing the page and region |
|
|
164
|
+
| `folder` | Copied recursively |
|
|
165
|
+
| `folder-contents` | Files copied flat into the destination |
|
|
166
|
+
|
|
167
|
+
Exported files are named `{sortOrder}_{label}.{ext}` so the order is preserved on disk.
|
|
168
|
+
|
|
169
|
+
To export, click the **⇩ Export** button in the collection detail header. You will be prompted for a destination path (relative to the content root).
|
|
170
|
+
|
|
171
|
+
The export endpoint is restricted to paths within the content root for safety — paths containing `..` or absolute paths are rejected.
|
|
172
|
+
|
|
144
173
|
## Data Storage
|
|
145
174
|
|
|
146
175
|
Collections are stored server-side as Bibliograph records. Each collection is a JSON document containing the collection metadata and its items array. The favorites collection uses a well-known GUID and is created automatically.
|
|
@@ -160,3 +189,4 @@ Client-side state (which collection is open, panel width, last-used collection)
|
|
|
160
189
|
| PUT | `/api/collections/:guid/reorder` | Reorder items (manual sort) |
|
|
161
190
|
| POST | `/api/collections/copy-items` | Copy items between collections |
|
|
162
191
|
| POST | `/api/collections/:guid/execute` | Execute pending operations (operation plans) |
|
|
192
|
+
| POST | `/api/collections/:guid/export` | Export the collection to a folder within the content root |
|
|
@@ -79,12 +79,86 @@ RUN apt-get update && apt-get install -y calibre && rm -rf /var/lib/apt/lists/*
|
|
|
79
79
|
|
|
80
80
|
## PDF Files
|
|
81
81
|
|
|
82
|
-
PDF files are rendered using
|
|
82
|
+
PDF files are rendered using a full **pdf.js** canvas pipeline. The library is loaded from CDN on first use; no server-side dependencies are required for basic display.
|
|
83
|
+
|
|
84
|
+
### Page Navigation
|
|
85
|
+
|
|
86
|
+
The controls bar exposes:
|
|
87
|
+
|
|
88
|
+
- **← Prev** / **Next →** — page navigation
|
|
89
|
+
- **Page input** — type a page number and press Enter to jump
|
|
90
|
+
- **Zoom In / Out / Fit** — adjust scale (0.25x – 5x)
|
|
91
|
+
|
|
92
|
+
### Text Selection
|
|
93
|
+
|
|
94
|
+
PDF.js renders an invisible text layer over the canvas, so native browser text selection works. Drag to select text, then click **💾 Save Selection** to capture it as a labeled region.
|
|
95
|
+
|
|
96
|
+
The capture stores: page number, selected text, optional label.
|
|
97
|
+
|
|
98
|
+
### Visual Region Selection
|
|
99
|
+
|
|
100
|
+
Click **✂ Select Region** to enter visual selection mode. A crosshair cursor appears over the page canvas. Drag a rectangle, release, and a label input appears in the controls bar.
|
|
101
|
+
|
|
102
|
+
The capture stores: page number, X/Y/Width/Height in PDF units (so the region remaps correctly at any zoom level), optional label.
|
|
103
|
+
|
|
104
|
+
### Server-Side Text Extraction
|
|
105
|
+
|
|
106
|
+
`GET /api/media/pdf-text?path=<file>&page=<num>` returns the extracted text for a specific page (via pdf-parse). This is useful for search indexing or for when you want the full text without selecting it manually.
|
|
107
|
+
|
|
108
|
+
## Convertible Document Formats
|
|
109
|
+
|
|
110
|
+
Beyond PDF/EPUB/MOBI, the viewer also handles `.doc`, `.docx`, `.rtf`, `.odt`, `.wpd`, `.wps`, `.pages`, `.odp`, `.ppt`, `.pptx`, `.ods`, `.xls`, and `.xlsx` files. These are converted to PDF on the fly via the embedded **Orator-Conversion** service, then displayed in the same pdf.js viewer.
|
|
111
|
+
|
|
112
|
+
### Conversion Pipeline
|
|
113
|
+
|
|
114
|
+
1. The browser opens a convertible document
|
|
115
|
+
2. Retold Remote shows a "Converting document to PDF..." spinner
|
|
116
|
+
3. The server calls `GET /api/media/doc-convert?path=<file>` which delegates to `orator-conversion`'s `doc-to-pdf` custom converter
|
|
117
|
+
4. The converter pipes the file through LibreOffice headless (`soffice --headless --convert-to pdf`)
|
|
118
|
+
5. Falls back to Calibre's `ebook-convert` if LibreOffice is unavailable
|
|
119
|
+
6. The resulting PDF is cached in the same Parime cache as ebooks (separate `manifest-pdf.json`)
|
|
120
|
+
7. The browser loads the PDF in the standard pdf.js viewer with full text and region selection
|
|
121
|
+
|
|
122
|
+
Conversion results are cached per file (keyed by path + mtime), so reopening the same document is instant after the first conversion.
|
|
123
|
+
|
|
124
|
+
### Required Tools
|
|
125
|
+
|
|
126
|
+
| Tool | Use |
|
|
127
|
+
|------|-----|
|
|
128
|
+
| **LibreOffice** (`soffice`) | Best fidelity for Word, RTF, ODT, WordPerfect, PowerPoint, Excel |
|
|
129
|
+
| **Calibre** (`ebook-convert`) | Fallback for documents LibreOffice can't handle |
|
|
130
|
+
|
|
131
|
+
Install at least one of them on the server. On macOS: `brew install --cask libreoffice` or `brew install calibre`.
|
|
132
|
+
|
|
133
|
+
## eBook Selection Features
|
|
134
|
+
|
|
135
|
+
The EPUB reader supports the same labeled-region capture pattern as PDF and image viewers.
|
|
136
|
+
|
|
137
|
+
### Save Text Selection
|
|
138
|
+
|
|
139
|
+
1. Select text in the rendered EPUB content (works through the epub.js iframe via `getContents()`)
|
|
140
|
+
2. Click **💾 Save Selection** in the controls bar
|
|
141
|
+
3. Enter a label and save
|
|
142
|
+
|
|
143
|
+
The capture stores:
|
|
144
|
+
|
|
145
|
+
- **CFI** (Canonical Fragment Identifier) — exact location for re-navigating later
|
|
146
|
+
- **Spine index** — which section of the book
|
|
147
|
+
- **Chapter title** — best-effort lookup from the TOC
|
|
148
|
+
- **Selected text** — the actual highlighted prose
|
|
149
|
+
|
|
150
|
+
Click a saved text selection in the **Regions** sidebar tab to navigate back to its exact location via `rendition.display(cfi)`.
|
|
151
|
+
|
|
152
|
+
### Visual Region Selection
|
|
153
|
+
|
|
154
|
+
Click **✂ Select Region** to overlay a transparent crosshair on the rendered page. Drag a rectangle to capture a visual area. The capture stores X/Y/Width/Height plus the viewport dimensions at capture time (so coordinates can be remapped if the window is resized later).
|
|
83
155
|
|
|
84
156
|
## Limitations
|
|
85
157
|
|
|
86
158
|
- MOBI conversion requires Calibre's `ebook-convert` on the server
|
|
159
|
+
- Document conversion (DOC, DOCX, RTF, etc.) requires LibreOffice or Calibre on the server
|
|
87
160
|
- DRM-protected ebooks cannot be read
|
|
88
161
|
- Complex EPUB layouts (fixed-layout EPUBs, heavy CSS) may not render perfectly
|
|
89
162
|
- The reader uses single-page mode only (no two-page spreads)
|
|
90
163
|
- Page numbers shown in the UI correspond to the reflowed content, not the original book pagination
|
|
164
|
+
- EPUB visual region coordinates are container-relative; they remap reasonably at different window sizes but are not perfectly stable across major layout reflows
|
|
@@ -51,11 +51,37 @@ If Sharp is not available on the server, the image loads directly regardless of
|
|
|
51
51
|
| `+` / `=` | Zoom in (1.5x) |
|
|
52
52
|
| `-` | Zoom out (1.5x) |
|
|
53
53
|
| `0` | Reset to home zoom (fit to view) |
|
|
54
|
-
| `
|
|
54
|
+
| `s` | Toggle region selection mode |
|
|
55
|
+
| `a` | Quick-add to active collection (current region if one is selected) |
|
|
55
56
|
| `b` | Toggle collection panel |
|
|
56
57
|
| `h` | Toggle favorite |
|
|
57
58
|
| `Esc` | Back to image viewer |
|
|
58
59
|
|
|
60
|
+
## Subimage Regions
|
|
61
|
+
|
|
62
|
+
Press `s` (or click the **✂ Select** button in the header) to enter region selection mode. The cursor changes to a crosshair and OpenSeadragon's drag-to-pan is temporarily disabled.
|
|
63
|
+
|
|
64
|
+
Drag a rectangle on the image. On release, an inline label input appears in the controls bar — type a name and hit Enter. The region is saved with these coordinates:
|
|
65
|
+
|
|
66
|
+
- **X, Y** — top-left corner in original image pixels
|
|
67
|
+
- **Width, Height** — dimensions in original image pixels
|
|
68
|
+
|
|
69
|
+
Saved regions render as gold-bordered overlays with floating label badges. They persist per file via the SubimageService and appear in the **Regions** sidebar tab.
|
|
70
|
+
|
|
71
|
+
### Region Actions
|
|
72
|
+
|
|
73
|
+
From the **Regions** sidebar tab you can:
|
|
74
|
+
|
|
75
|
+
- 🔍 **Navigate** — zoom the explorer to the saved region (`viewport.fitBounds(imageRect)`)
|
|
76
|
+
- ➕ **Add to Collection** — saves as an `image-crop` collection item with the original-pixel `CropRegion`
|
|
77
|
+
- 🗑️ **Delete** — removes the region
|
|
78
|
+
|
|
79
|
+
### Multiple Regions
|
|
80
|
+
|
|
81
|
+
You can save unlimited labeled regions per image. They never lose resolution because the coordinates are stored in the original image pixel space, not in viewport pixels. When the collection is exported, each region is cropped at full resolution via `sharp.extract()`.
|
|
82
|
+
|
|
83
|
+
This same labeling pattern works on CBZ/CBR comic pages (each page is a regular image inside an archive — no special handling needed) and is the foundation for the document region system in the EPUB and PDF viewers.
|
|
84
|
+
|
|
59
85
|
## Coordinate Display
|
|
60
86
|
|
|
61
87
|
In DZI tile mode, the info bar shows the pixel coordinates of the point under the cursor in real time (e.g., "(4096, 3072)"). This updates as the mouse moves across the canvas and reflects the actual pixel position in the original full-resolution image.
|
|
@@ -21,31 +21,31 @@ The build step bundles the client-side JavaScript with Quackage and copies asset
|
|
|
21
21
|
|
|
22
22
|
## Running the Server
|
|
23
23
|
|
|
24
|
-
### CLI
|
|
24
|
+
### CLI Commands
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
retold-remote serve [content-path] [options]
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Or using the short alias:
|
|
26
|
+
There are three bin entries provided by the `retold-remote` package:
|
|
31
27
|
|
|
32
28
|
```bash
|
|
33
|
-
|
|
29
|
+
retold-remote serve [content-path] [options] # full form
|
|
30
|
+
rr serve [content-path] [options] # short alias
|
|
31
|
+
retold-stack [content-path] [options] # convenience: serve --stack
|
|
34
32
|
```
|
|
35
33
|
|
|
36
34
|
If `content-path` is omitted, the current directory is served.
|
|
37
35
|
|
|
36
|
+
The `retold-stack` shortcut auto-injects `serve --stack`, which spawns Ultravisor as a child process and uses XDG-style data paths. See [Stack Launcher](stack-launcher.md) for the full story.
|
|
37
|
+
|
|
38
38
|
### Options
|
|
39
39
|
|
|
40
40
|
| Flag | Description | Default |
|
|
41
41
|
|------|-------------|---------|
|
|
42
42
|
| `-p, --port [port]` | Port to listen on | Random 7000-7999 |
|
|
43
|
-
|
|
|
44
|
-
| `-c, --cache-path [path]` | Root cache directory | `./dist/retold-cache/` |
|
|
45
|
-
| `--cache-
|
|
46
|
-
|
|
|
47
|
-
| `--
|
|
48
|
-
|
|
|
43
|
+
| `--no-hash` | Disable hashed filename mode (use plain paths in URLs) | Hashing on |
|
|
44
|
+
| `-c, --cache-path [path]` | Root cache directory | `./dist/retold-cache/` (or `~/.cache/retold-remote/` in stack mode) |
|
|
45
|
+
| `--cache-server [url]` | URL of a remote Parime cache server | None |
|
|
46
|
+
| `-u, --ultravisor [url]` | Connect to an Ultravisor mesh; URL defaults to `http://localhost:54321` if omitted | None |
|
|
47
|
+
| `--stack` | Spawn Ultravisor as a child process and connect to it. Uses XDG-style data paths under `~/.local/share` and `~/.cache`. See [Stack Launcher](stack-launcher.md) | Off |
|
|
48
|
+
| `-l, --logfile [path]` | Write logs to a file (auto-generates timestamped name if path omitted) | Console only |
|
|
49
49
|
|
|
50
50
|
### Direct Node.js
|
|
51
51
|
|
|
@@ -65,20 +65,30 @@ Default port is `8086` when using `server.js` directly.
|
|
|
65
65
|
### Examples
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
# Serve current directory on port
|
|
69
|
-
|
|
68
|
+
# Serve current directory on a random port
|
|
69
|
+
retold-remote serve
|
|
70
70
|
|
|
71
71
|
# Serve a specific folder
|
|
72
|
-
|
|
72
|
+
retold-remote serve /mnt/nas/media
|
|
73
73
|
|
|
74
74
|
# CLI with custom port
|
|
75
75
|
retold-remote serve /mnt/nas/media -p 3000
|
|
76
76
|
|
|
77
|
-
#
|
|
78
|
-
retold-remote serve /mnt/nas/media -
|
|
77
|
+
# Plain paths in URLs (disable hashing)
|
|
78
|
+
retold-remote serve /mnt/nas/media --no-hash
|
|
79
79
|
|
|
80
80
|
# Custom cache location (useful for Docker volumes)
|
|
81
81
|
retold-remote serve /media -c /cache
|
|
82
|
+
|
|
83
|
+
# Connect to an existing Ultravisor mesh
|
|
84
|
+
retold-remote serve /media -u http://192.168.1.100:54321
|
|
85
|
+
|
|
86
|
+
# Full stack: spawn Ultravisor as a child process, embed Orator-Conversion,
|
|
87
|
+
# use XDG paths (~/.local/share/ultravisor, ~/.cache/retold-remote)
|
|
88
|
+
retold-stack /mnt/nas/media
|
|
89
|
+
|
|
90
|
+
# Same thing via the explicit flag
|
|
91
|
+
retold-remote serve --stack /mnt/nas/media
|
|
82
92
|
```
|
|
83
93
|
|
|
84
94
|
## Configuration
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Stack Launcher
|
|
2
|
+
|
|
3
|
+
The `--stack` flag (and the `retold-stack` shortcut) brings up the full Retold stack as a single command: an embedded Ultravisor coordinator, the Retold Remote media browser, and Orator-Conversion (embedded inside Retold Remote). Point it at any directory and it just works — sane XDG-style data paths, automatic readiness polling, and graceful shutdown of all child processes.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Run the full stack against the current directory
|
|
9
|
+
retold-stack
|
|
10
|
+
|
|
11
|
+
# Or against any directory
|
|
12
|
+
retold-stack /mnt/nas/media
|
|
13
|
+
|
|
14
|
+
# Or via the explicit flag
|
|
15
|
+
retold-remote serve --stack /mnt/nas/media
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That's it. No config files, no separate terminals, no manual port wiring.
|
|
19
|
+
|
|
20
|
+
## What Gets Launched
|
|
21
|
+
|
|
22
|
+
| Component | Where it runs | Port |
|
|
23
|
+
|-----------|---------------|------|
|
|
24
|
+
| **Ultravisor** | Spawned as a child process | 54321 |
|
|
25
|
+
| **Retold Remote** | Main process (the one you started) | Random 7000-7999 (override with `-p`) |
|
|
26
|
+
| **Orator-Conversion** | Embedded inside Retold Remote (no separate process) | Same as Retold Remote |
|
|
27
|
+
|
|
28
|
+
The stack launcher:
|
|
29
|
+
1. Resolves XDG-style data paths
|
|
30
|
+
2. Detects whether Ultravisor is already running on port 54321 (and reuses it if so)
|
|
31
|
+
3. Spawns Ultravisor as a child process with a generated config file
|
|
32
|
+
4. Polls until Ultravisor is accepting connections (up to 30 seconds)
|
|
33
|
+
5. Sets the `UltravisorURL` automatically so Retold Remote registers as a beacon
|
|
34
|
+
6. Starts the Retold Remote server with Orator-Conversion embedded
|
|
35
|
+
7. Streams the Ultravisor child's stdout/stderr through the main logger with an `[ultravisor]` prefix
|
|
36
|
+
8. On `SIGINT`/`SIGTERM`, disconnects the beacon, kills the Ultravisor child gracefully, and exits
|
|
37
|
+
|
|
38
|
+
## Default Data Paths
|
|
39
|
+
|
|
40
|
+
The stack launcher uses [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) defaults so data lives in predictable, user-scoped locations regardless of what directory you launched from.
|
|
41
|
+
|
|
42
|
+
| Purpose | Default Path | Override |
|
|
43
|
+
|---------|-------------|----------|
|
|
44
|
+
| Ultravisor datastore | `~/.local/share/ultravisor/datastore/` | `$XDG_DATA_HOME/ultravisor/datastore/` |
|
|
45
|
+
| Ultravisor staging | `~/.local/share/ultravisor/staging/` | `$XDG_DATA_HOME/ultravisor/staging/` |
|
|
46
|
+
| Retold Remote cache | `~/.cache/retold-remote/` | `$XDG_CACHE_HOME/retold-remote/`, or `-c` flag |
|
|
47
|
+
| Stack config files | `~/.config/retold-stack/` | `$XDG_CONFIG_HOME/retold-stack/` |
|
|
48
|
+
|
|
49
|
+
The cache directory holds thumbnails, video frames, audio waveforms, archive extractions, and converted ebooks/PDFs.
|
|
50
|
+
|
|
51
|
+
The Ultravisor datastore holds the work-queue journal and beacon registry.
|
|
52
|
+
|
|
53
|
+
These paths are created on first launch if they do not already exist.
|
|
54
|
+
|
|
55
|
+
## CLI Reference
|
|
56
|
+
|
|
57
|
+
### `retold-stack`
|
|
58
|
+
|
|
59
|
+
Convenience entry point that auto-injects `serve --stack`.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
retold-stack [content-path] [options]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
All options accepted by `retold-remote serve` are forwarded.
|
|
66
|
+
|
|
67
|
+
### `retold-remote serve --stack`
|
|
68
|
+
|
|
69
|
+
The full form. Useful when you want to combine `--stack` with other flags.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
retold-remote serve --stack [content-path] [options]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| Flag | Description |
|
|
76
|
+
|------|-------------|
|
|
77
|
+
| `--stack` | Spawn Ultravisor as a child process and connect to it. Sets cache root to `~/.cache/retold-remote/` if `-c` is not passed. Auto-sets the Ultravisor URL to `http://localhost:54321`. |
|
|
78
|
+
|
|
79
|
+
All other `serve` options still apply (`-p`, `--no-hash`, `-c`, `-l`, etc.).
|
|
80
|
+
|
|
81
|
+
## Examples
|
|
82
|
+
|
|
83
|
+
### Browse the current directory with the full stack
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cd ~/Pictures
|
|
87
|
+
retold-stack
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Browse a specific NAS share
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
retold-stack /mnt/nas/media
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Pin the port and stash logs to a file
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
retold-stack /mnt/nas/media -p 8086 -l ~/retold.log
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Override just the Retold cache location
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
retold-remote serve --stack /mnt/nas/media -c /var/cache/retold
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Reuse an already-running Ultravisor
|
|
109
|
+
|
|
110
|
+
If port 54321 is already accepting connections, the stack launcher detects this and connects to the existing instance instead of spawning a new one. The log line will read:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
[stack] ultravisor already running on port 54321, reusing
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This means you can leave Ultravisor running across multiple Retold Remote launches without conflict.
|
|
117
|
+
|
|
118
|
+
## Logging
|
|
119
|
+
|
|
120
|
+
The stack launcher streams the Ultravisor child process's output through Retold Remote's logger so you have a single log stream for both processes. Lines from the Ultravisor child are prefixed `[ultravisor]`, and stack-launcher events are prefixed `[stack]`:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
[stack] launching ultravisor (port 54321)
|
|
124
|
+
[stack] data: /Users/steven/.local/share/ultravisor/datastore
|
|
125
|
+
[stack] staging: /Users/steven/.local/share/ultravisor/staging
|
|
126
|
+
[ultravisor] UltravisorTaskTypeRegistry: 53 built-in task types registered.
|
|
127
|
+
[stack] ultravisor ready (after 1 attempts)
|
|
128
|
+
==========================================================
|
|
129
|
+
Retold Remote running on http://localhost:7842
|
|
130
|
+
==========================================================
|
|
131
|
+
Content: /mnt/nas/media
|
|
132
|
+
Cache: /Users/steven/.cache/retold-remote
|
|
133
|
+
Browse: http://localhost:7842/
|
|
134
|
+
Beacon: registered with Ultravisor at http://localhost:54321
|
|
135
|
+
Stack: ultravisor + retold-remote (orator-conversion embedded)
|
|
136
|
+
==========================================================
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If you also pass `-l <path>`, both streams are written to the file as well.
|
|
140
|
+
|
|
141
|
+
## Shutdown
|
|
142
|
+
|
|
143
|
+
Press `Ctrl+C` once. The launcher will:
|
|
144
|
+
|
|
145
|
+
1. Log `Shutting down...`
|
|
146
|
+
2. Disconnect the Ultravisor beacon (so Ultravisor knows the worker is leaving cleanly)
|
|
147
|
+
3. Send `SIGTERM` to the Ultravisor child process
|
|
148
|
+
4. Wait up to 1 second for graceful exit
|
|
149
|
+
5. Send `SIGKILL` if it has not exited
|
|
150
|
+
6. Exit the main process
|
|
151
|
+
|
|
152
|
+
If the launcher reused an already-running Ultravisor (rather than spawning one), it will not kill that Ultravisor — it only manages processes it started itself.
|
|
153
|
+
|
|
154
|
+
## Architecture
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
┌────────────────────────────────────────────────────────────┐
|
|
158
|
+
│ retold-stack /mnt/media │
|
|
159
|
+
│ │
|
|
160
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
161
|
+
│ │ Main process (retold-remote) │ │
|
|
162
|
+
│ │ ┌───────────────────────────────────────────────┐ │ │
|
|
163
|
+
│ │ │ Orator HTTP server (port 7000-7999) │ │ │
|
|
164
|
+
│ │ │ ├─ Retold Remote routes (/api/media/...) │ │ │
|
|
165
|
+
│ │ │ ├─ Orator-Conversion (/api/conversion/1.0/) │ │ │
|
|
166
|
+
│ │ │ └─ Static web app (/) │ │ │
|
|
167
|
+
│ │ └───────────────────────────────────────────────┘ │ │
|
|
168
|
+
│ │ ┌───────────────────────────────────────────────┐ │ │
|
|
169
|
+
│ │ │ Ultravisor Beacon client │ │ │
|
|
170
|
+
│ │ │ └─ Connects to localhost:54321 │ │ │
|
|
171
|
+
│ │ └───────────────────────────────────────────────┘ │ │
|
|
172
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
173
|
+
│ ▲ │
|
|
174
|
+
│ │ HTTP │
|
|
175
|
+
│ ▼ │
|
|
176
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
177
|
+
│ │ Child process (ultravisor) │ │
|
|
178
|
+
│ │ ├─ Coordinator API (port 54321) │ │
|
|
179
|
+
│ │ ├─ Beacon registry │ │
|
|
180
|
+
│ │ ├─ Work queue journal │ │
|
|
181
|
+
│ │ └─ Web interface │ │
|
|
182
|
+
│ │ Datastore: ~/.local/share/ultravisor/datastore/ │ │
|
|
183
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
184
|
+
└────────────────────────────────────────────────────────────┘
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Why Stack Mode?
|
|
188
|
+
|
|
189
|
+
Use `--stack` when you want a single command that brings up the full Retold experience:
|
|
190
|
+
|
|
191
|
+
- **Heavy media processing offloaded** through the Ultravisor beacon (video frame extraction, audio waveforms, ebook conversion, PDF page rendering)
|
|
192
|
+
- **Document conversion** via the embedded Orator-Conversion service (with the `doc-to-pdf` converter for Word, RTF, ODT, WordPerfect, etc.)
|
|
193
|
+
- **Persistent state** across launches (the Ultravisor datastore lives at a stable XDG location)
|
|
194
|
+
- **No port juggling** — Ultravisor on its standard port 54321, Retold Remote on a random high port
|
|
195
|
+
|
|
196
|
+
Use the bare `retold-remote serve` command (without `--stack`) when you just want a quick gallery browser without the coordinator infrastructure.
|
|
197
|
+
|
|
198
|
+
## Comparison
|
|
199
|
+
|
|
200
|
+
| Feature | `retold-remote serve` | `retold-stack` |
|
|
201
|
+
|---------|----------------------|----------------|
|
|
202
|
+
| Gallery browser | ✓ | ✓ |
|
|
203
|
+
| Image/video/audio viewers | ✓ | ✓ |
|
|
204
|
+
| Document conversion (doc, rtf, etc.) | Embedded only | Embedded + dispatched |
|
|
205
|
+
| Heavy work offloading | No | Yes (via Ultravisor) |
|
|
206
|
+
| Spawns child processes | No | Yes (Ultravisor) |
|
|
207
|
+
| Default cache location | `./dist/retold-cache/` | `~/.cache/retold-remote/` |
|
|
208
|
+
| Survives `cd` | Yes | Yes (XDG paths are absolute) |
|
|
209
|
+
|
|
210
|
+
## Troubleshooting
|
|
211
|
+
|
|
212
|
+
| Symptom | Fix |
|
|
213
|
+
|---------|-----|
|
|
214
|
+
| `Could not locate the ultravisor package` | Run `npm install ultravisor` (or `npm install -g retold-remote` to get the bundled version) |
|
|
215
|
+
| `Ultravisor did not become ready within 30000ms` | Check the `[ultravisor]` log lines for an error. Common causes: port 54321 already bound by another process, missing dependencies, or invalid datastore path permissions |
|
|
216
|
+
| Stack mode hangs at `launching ultravisor` | Ultravisor's child process may be waiting on stdin or hitting an interactive prompt. Run with `-l <path>` to capture full logs |
|
|
217
|
+
| Beacon shows "not connected" | Ultravisor came up but the beacon registration failed. Check the Ultravisor child logs for errors and verify nothing is firewalling localhost:54321 |
|
|
218
|
+
| Want to override XDG paths | Set `XDG_DATA_HOME`, `XDG_CACHE_HOME`, or `XDG_CONFIG_HOME` in your environment before launching, or use the `-c` flag for the Retold Remote cache |
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
retold-remote can offload heavy media processing to a remote machine running an Ultravisor beacon worker. This is useful when the server (e.g. a NAS) has limited CPU and RAM but needs to process large video files, raw camera images, audio waveforms, and ebook conversions.
|
|
4
4
|
|
|
5
|
+
> **Tip:** If you just want to run Ultravisor and Retold Remote together on the same machine without configuring anything, use the [Stack Launcher](stack-launcher.md) — `retold-stack /path/to/media` spawns Ultravisor as a child process automatically with sane XDG-style data paths. This page covers the case where Ultravisor runs on a *different* machine.
|
|
6
|
+
|
|
5
7
|
## How It Works
|
|
6
8
|
|
|
7
9
|
When configured, retold-remote dispatches shell commands (ffmpeg, ffprobe, dcraw, ImageMagick, audiowaveform, ebook-convert) to a beacon worker via HTTP instead of running them locally. The beacon downloads the source file from retold-remote's content API, executes the command, and returns the result as base64-encoded data.
|