retold-remote 0.0.23 → 0.0.26

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.
Files changed (79) hide show
  1. package/css/retold-remote.css +343 -20
  2. package/docs/.nojekyll +0 -0
  3. package/docs/README.md +64 -12
  4. package/docs/_cover.md +6 -6
  5. package/docs/_sidebar.md +2 -0
  6. package/docs/_topbar.md +1 -1
  7. package/docs/_version.json +7 -0
  8. package/docs/collections.md +30 -0
  9. package/docs/css/docuserve.css +327 -0
  10. package/docs/ebook-reader.md +75 -1
  11. package/docs/image-explorer.md +62 -2
  12. package/docs/index.html +39 -0
  13. package/docs/retold-catalog.json +254 -0
  14. package/docs/retold-keyword-index.json +31216 -0
  15. package/docs/server-setup.md +122 -91
  16. package/docs/stack-launcher.md +218 -0
  17. package/docs/synology.md +585 -0
  18. package/docs/ultravisor-configuration.md +5 -5
  19. package/docs/ultravisor-integration.md +4 -2
  20. package/package.json +20 -14
  21. package/source/Pict-Application-RetoldRemote.js +22 -0
  22. package/source/RetoldRemote-ExtensionMaps.js +1 -1
  23. package/source/cli/RetoldRemote-Server-Setup.js +460 -7
  24. package/source/cli/RetoldRemote-Stack-Launcher.js +563 -0
  25. package/source/cli/RetoldRemote-Stack-Run.js +41 -0
  26. package/source/cli/commands/RetoldRemote-Command-Serve.js +129 -54
  27. package/source/providers/CollectionManager-AddItems.js +166 -0
  28. package/source/providers/Pict-Provider-GalleryNavigation.js +55 -0
  29. package/source/providers/Pict-Provider-OperationStatus.js +597 -0
  30. package/source/providers/keyboard-handlers/KeyHandler-ImageExplorer.js +20 -1
  31. package/source/providers/keyboard-handlers/KeyHandler-Viewer.js +23 -0
  32. package/source/server/RetoldRemote-AudioWaveformService.js +49 -3
  33. package/source/server/RetoldRemote-CollectionExportService.js +763 -0
  34. package/source/server/RetoldRemote-CollectionService.js +5 -0
  35. package/source/server/RetoldRemote-EbookService.js +218 -3
  36. package/source/server/RetoldRemote-ImageService.js +221 -46
  37. package/source/server/RetoldRemote-MediaService.js +63 -4
  38. package/source/server/RetoldRemote-MetadataCache.js +25 -5
  39. package/source/server/RetoldRemote-OperationBroadcaster.js +363 -0
  40. package/source/server/RetoldRemote-SubimageService.js +680 -0
  41. package/source/server/RetoldRemote-ToolDetector.js +50 -0
  42. package/source/server/RetoldRemote-UltravisorBeacon.js +18 -3
  43. package/source/server/RetoldRemote-UltravisorDispatcher.js +65 -491
  44. package/source/server/RetoldRemote-UltravisorOperations.js +133 -20
  45. package/source/server/RetoldRemote-VideoFrameService.js +302 -9
  46. package/source/views/MediaViewer-EbookViewer.js +419 -1
  47. package/source/views/MediaViewer-PdfViewer.js +1050 -0
  48. package/source/views/PictView-Remote-AudioExplorer.js +77 -1
  49. package/source/views/PictView-Remote-CollectionsPanel.js +213 -0
  50. package/source/views/PictView-Remote-Gallery.js +365 -64
  51. package/source/views/PictView-Remote-ImageExplorer.js +1529 -44
  52. package/source/views/PictView-Remote-ImageViewer.js +2 -2
  53. package/source/views/PictView-Remote-Layout.js +58 -0
  54. package/source/views/PictView-Remote-MediaViewer.js +100 -25
  55. package/source/views/PictView-Remote-RegionsBrowser.js +554 -0
  56. package/source/views/PictView-Remote-SubimagesPanel.js +353 -0
  57. package/source/views/PictView-Remote-TopBar.js +1 -0
  58. package/source/views/PictView-Remote-VideoExplorer.js +77 -1
  59. package/web-application/css/docuserve.css +277 -23
  60. package/web-application/css/retold-remote.css +343 -20
  61. package/web-application/docs/README.md +64 -12
  62. package/web-application/docs/_cover.md +6 -6
  63. package/web-application/docs/_sidebar.md +2 -0
  64. package/web-application/docs/_topbar.md +1 -1
  65. package/web-application/docs/collections.md +30 -0
  66. package/web-application/docs/ebook-reader.md +75 -1
  67. package/web-application/docs/image-explorer.md +62 -2
  68. package/web-application/docs/server-setup.md +122 -91
  69. package/web-application/docs/stack-launcher.md +218 -0
  70. package/web-application/docs/synology.md +585 -0
  71. package/web-application/docs/ultravisor-configuration.md +5 -5
  72. package/web-application/docs/ultravisor-integration.md +4 -2
  73. package/web-application/js/pict-docuserve.min.js +12 -12
  74. package/web-application/js/pict.min.js +2 -2
  75. package/web-application/js/pict.min.js.map +1 -1
  76. package/web-application/retold-remote.js +6596 -1784
  77. package/web-application/retold-remote.js.map +1 -1
  78. package/web-application/retold-remote.min.js +75 -23
  79. package/web-application/retold-remote.min.js.map +1 -1
@@ -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 the browser's native PDF viewer in an iframe. No additional tools or libraries are required. The browser provides its own controls for page navigation, zoom, and search.
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,10 +51,70 @@ 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
- | `a` | Quick-add to active collection |
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
- | `Esc` | Back to image viewer |
58
+ | `Esc` | Unwind one layer: exit edit mode -> exit selection mode -> back to viewer |
59
+
60
+ `Esc` is layered: if you are editing a saved region, the first `Esc` exits edit mode; if you are drawing a new region, it cancels the draw; otherwise it closes the explorer.
61
+
62
+ ## Subimage Regions
63
+
64
+ 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.
65
+
66
+ 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:
67
+
68
+ - **X, Y** -- top-left corner in original image pixels
69
+ - **Width, Height** -- dimensions in original image pixels
70
+
71
+ 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. Overlays are restored automatically whenever you reopen the image, including after the tile-viewer swap for DZI-mode images.
72
+
73
+ ### Editing Existing Regions
74
+
75
+ Double-click any saved region overlay to enter **edit mode**. The selected region is highlighted, the other regions dim to 35% opacity, and eight drag handles appear (four corners + four edges). Each handle has a larger invisible hit area around a small visible dot so it's easy to grab on both mouse and touch.
76
+
77
+ In edit mode you can:
78
+
79
+ - **Resize** -- drag a corner or edge handle. Dragging past the opposite edge flips the rectangle (so you can go from tl-drag to br-drag without re-entering edit mode).
80
+ - **Move** -- drag the body of the region.
81
+ - **Edit label** -- the inline label input in the controls bar is pre-filled with the current label. Change it and press `Enter` (or click Save).
82
+ - **Cancel** -- click the Cancel button, press `Esc`, or double-click a different region.
83
+
84
+ Geometry and label changes are **optimistic**: they apply locally the instant you release the drag or press Enter, then fire a `PUT /api/media/subimage-regions/:id` in the background. If the server request fails (e.g., because the file's mtime changed since the region was loaded), the change reverts and a toast explains the failure.
85
+
86
+ While in edit mode OpenSeadragon's mouse navigation (pan/zoom/click-to-zoom) is suspended inside the region rectangle so drags on the handles or body don't also pan the viewer. Clicks outside any region still pan normally.
87
+
88
+ Edit mode is mutually exclusive with new-region draw mode: entering one automatically exits the other.
89
+
90
+ ### Region Actions
91
+
92
+ From the **Regions** sidebar tab you can:
93
+
94
+ - **Navigate** -- zoom the explorer to the saved region (`viewport.fitBounds(imageRect)`)
95
+ - **Add to Collection** -- saves as an `image-crop` collection item with the original-pixel `CropRegion`
96
+ - **Delete** -- removes the region
97
+
98
+ The Regions sidebar auto-refreshes when you navigate between files -- you no longer have to click the Regions tab after switching images.
99
+
100
+ ### Multiple Regions
101
+
102
+ 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()`.
103
+
104
+ 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.
105
+
106
+ ### Regions Browser
107
+
108
+ The topbar **▣ Regions Browser** button opens a full-screen folder-scoped view of every saved region across every file. This scales cleanly to thousands of regions because the server maintains an in-memory cache keyed on the Bibliograph enumeration, invalidated only on mutations.
109
+
110
+ Layout:
111
+
112
+ - **Left** -- folder tree with per-folder region counts. Click a folder to filter the right pane. "All folders" shows every region across the content root.
113
+ - **Right** -- files in the selected folder, each with a header showing the filename and region count, followed by the regions as clickable chips (label + dimensions).
114
+
115
+ Click a region chip to close the browser, open the file in the appropriate viewer (image explorer for images, media viewer for PDFs/EPUBs), and jump to the region's coordinates.
116
+
117
+ The initial folder selection is seeded from the gallery's current browsing location, so opening the browser from a folder you're browsing shows just that folder's regions by default. Press `Esc` or the ** Close** button to dismiss.
58
118
 
59
119
  ## Coordinate Display
60
120
 
@@ -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 Command
24
+ ### CLI Commands
25
25
 
26
- ```bash
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
- rr serve /path/to/media
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
- | `-H, --hashed-filenames` | Enable hashed filename mode (hides real paths from browser) | Off |
44
- | `-c, --cache-path [path]` | Root cache directory | `./dist/retold-cache/` |
45
- | `--cache-thumbnails [path]` | Override thumbnail cache location | `<cache-root>/thumbnails/` |
46
- | `--cache-archives [path]` | Override archive extraction cache | `<cache-root>/archives/` |
47
- | `--cache-video-frames [path]` | Override video frame cache | `<cache-root>/video-frames/` |
48
- | `--cache-audio-waveforms [path]` | Override audio waveform cache | `<cache-root>/audio-waveforms/` |
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 8086
69
- node server.js
68
+ # Serve current directory on a random port
69
+ retold-remote serve
70
70
 
71
71
  # Serve a specific folder
72
- node server.js /mnt/nas/media
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
- # Hashed filenames for privacy
78
- retold-remote serve /mnt/nas/media -H
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
@@ -131,111 +141,132 @@ When enabled (`-H` flag or `RETOLD_HASHED_FILENAMES=true`), real file paths are
131
141
 
132
142
  ## Docker
133
143
 
134
- ### Using the Included Dockerfile
144
+ Retold Remote ships with two Dockerfiles, a `docker-compose.yml`, and a `docker-build-and-save.sh` helper. All images run the full stack (Ultravisor + Retold Remote + embedded Orator-Conversion) as a single container.
145
+
146
+ > **Running on Synology?** See the dedicated [Synology Container Manager](synology.md) guide for a step-by-step walkthrough including how to build the image on a dev machine and transfer it to the NAS.
135
147
 
136
- A `Dockerfile` is provided in the repository root:
148
+ ### Quick Start (any Docker host with the source tree)
149
+
150
+ The compose file defaults to `image: retold-stack:latest` so it works on hosts that already have the image loaded. To build and run from the source tree in one go:
137
151
 
138
152
  ```bash
139
- docker build -t retold-remote .
140
- docker run -p 8086:8086 -v /path/to/media:/media retold-remote
153
+ cd retold-remote
154
+
155
+ # Build the image and tag it as retold-stack:latest
156
+ docker build -t retold-stack:latest .
157
+
158
+ # Start the stack
159
+ MEDIA_PATH=/path/to/your/media docker compose up -d
141
160
  ```
142
161
 
143
- ### Inline Dockerfile
162
+ Then browse to `http://localhost:7777/`. The Ultravisor coordinator web interface is at `http://localhost:54321/`.
144
163
 
145
- If you need to create a Dockerfile from scratch, here is a complete working version:
164
+ If you'd rather have Compose build the image directly, edit `docker-compose.yml`:
165
+
166
+ ```yaml
167
+ services:
168
+ retold-stack:
169
+ # image: retold-stack:latest # <- comment this out
170
+ build: # <- uncomment this block
171
+ context: .
172
+ dockerfile: Dockerfile
173
+ ```
146
174
 
147
- ```dockerfile
148
- FROM node:20-slim
175
+ Then `docker compose up -d --build` will build and start in one step.
149
176
 
150
- # Install optional tools for full functionality
151
- RUN apt-get update && apt-get install -y --no-install-recommends \
152
- ffmpeg \
153
- imagemagick \
154
- p7zip-full \
155
- calibre \
156
- && rm -rf /var/lib/apt/lists/*
177
+ ### Dockerfile Variants
157
178
 
158
- WORKDIR /app
179
+ Both images have been verified to build and run the full stack on ARM64 (Apple Silicon) and should build identically on AMD64.
159
180
 
160
- # Copy package files and install dependencies
161
- COPY package.json package-lock.json ./
162
- RUN npm ci --omit=dev && npm cache clean --force
181
+ | File | Measured Size | Includes | Use for |
182
+ |------|---------------|----------|---------|
183
+ | `Dockerfile` | **3.0 GB** | Everything: ffmpeg, ImageMagick, 7z, poppler, pdftk, LibreOffice, Calibre, exiftool, dcraw | Full document conversion (DOC, DOCX, RTF, ODT, WPD, MOBI, PPT, XLS, etc.) |
184
+ | `Dockerfile.slim` | **1.81 GB** | Same but without LibreOffice and Calibre | Image/video/audio/PDF/EPUB only -- no doc/docx/mobi conversion |
163
185
 
164
- # Install sharp (optional image processing)
165
- RUN npm install sharp || true
186
+ > **Note on audiowaveform:** Neither image installs `audiowaveform` because it is not in the default Debian repositories. Retold Remote automatically falls back to ffprobe + ffmpeg for waveform generation, which is slower but works identically. If you need the BBC `audiowaveform` tool for faster generation, add it via a custom Dockerfile step (build from source or a PPA).
166
187
 
167
- # Copy application source and built assets
168
- COPY source/ source/
169
- COPY web-application/ web-application/
170
- COPY css/ css/
171
- COPY html/ html/
172
- COPY server.js ./
188
+ ### Building and Saving for Transfer
173
189
 
174
- # Create cache directory
175
- RUN mkdir -p /cache
190
+ For deploying to a NAS or any host that doesn't have the source tree, use the `docker-build-and-save.sh` helper:
176
191
 
177
- # Default port
178
- ENV PORT=8086
192
+ ```bash
193
+ ./docker-build-and-save.sh # full image, host architecture
194
+ ./docker-build-and-save.sh slim # slim variant
195
+ ./docker-build-and-save.sh --amd64 # cross-build for x86_64
196
+ ./docker-build-and-save.sh slim --arm64 # slim + arm64
197
+ ```
179
198
 
180
- EXPOSE 8086
199
+ This produces a compressed tar file (`retold-stack-image.tar.gz` or `retold-stack-image-slim.tar.gz`) that you can copy to the target host and load with:
181
200
 
182
- # Serve /media with cache at /cache
183
- CMD ["node", "server.js", "/media"]
201
+ ```bash
202
+ docker load -i retold-stack-image.tar.gz
184
203
  ```
185
204
 
186
- ### Docker Compose
205
+ Then start the stack with the included `docker-compose.yml` (which references `retold-stack:latest` by default). No source tree needed on the target host.
187
206
 
188
- ```yaml
189
- version: "3.8"
190
- services:
191
- retold-remote:
192
- build: .
193
- ports:
194
- - "8086:8086"
195
- volumes:
196
- - /path/to/media:/media:ro
197
- - retold-cache:/cache
198
- environment:
199
- - PORT=8086
200
- restart: unless-stopped
201
-
202
- volumes:
203
- retold-cache:
207
+ ### Manual Docker Run
208
+
209
+ If you prefer `docker run` over Compose:
210
+
211
+ ```bash
212
+ docker build -t retold-stack .
213
+
214
+ docker run -d \
215
+ --name retold-stack \
216
+ -p 7777:7777 \
217
+ -p 54321:54321 \
218
+ -v /path/to/media:/media:ro \
219
+ -v retold-cache:/cache \
220
+ -v ultravisor-data:/data \
221
+ -v retold-config:/config \
222
+ --restart unless-stopped \
223
+ retold-stack
204
224
  ```
205
225
 
206
- ### Docker Usage Notes
226
+ Then browse to `http://localhost:7777/`.
227
+
228
+ ### Volume Mounts
207
229
 
208
- - Mount your media folder to `/media` (read-only is fine with `:ro`)
209
- - Mount a volume to `/cache` for persistent thumbnail and frame caches
210
- - The `node:20-slim` base keeps the image small while the `apt-get` packages add full media processing
211
- - `calibre` is the largest optional package; omit it if you do not need MOBI/AZW ebook conversion
212
- - `sharp` is installed separately because it has native bindings that may fail on some architectures; the `|| true` ensures the build continues without it
230
+ The stack uses four volume mount points. The first is your media; the other three are for persistent state:
213
231
 
214
- ### Minimal Dockerfile (No Optional Tools)
232
+ | Container path | Purpose | Typical host mapping |
233
+ |----------------|---------|---------------------|
234
+ | `/media` | Media folder to browse (read-only) | `/path/to/media:/media:ro` |
235
+ | `/cache` | Thumbnails, frames, waveforms, conversions | Named volume `retold-cache` |
236
+ | `/data` | Ultravisor datastore + staging | Named volume `ultravisor-data` |
237
+ | `/config` | Stack config files | Named volume `retold-config` |
215
238
 
216
- If you only need basic browsing without thumbnails or media probing:
239
+ Inside the container, `XDG_CACHE_HOME`, `XDG_DATA_HOME`, and `XDG_CONFIG_HOME` are set to these paths so the stack launcher uses them automatically.
217
240
 
218
- ```dockerfile
219
- FROM node:20-slim
241
+ ### Published Ports
220
242
 
221
- WORKDIR /app
243
+ | Port | Purpose |
244
+ |------|---------|
245
+ | **7777** | Retold Remote web UI (the main thing you browse to) |
246
+ | **54321** | Ultravisor coordinator API + web interface (optional -- useful for monitoring) |
222
247
 
223
- COPY package.json package-lock.json ./
224
- RUN npm ci --omit=dev && npm cache clean --force
248
+ Both are pinned to fixed ports via the `-p 7777` flag in the default CMD, overriding the usual random 7000-7999 behavior.
225
249
 
226
- COPY source/ source/
227
- COPY web-application/ web-application/
228
- COPY css/ css/
229
- COPY html/ html/
230
- COPY server.js ./
250
+ ### Customizing the CMD
231
251
 
232
- ENV PORT=8086
233
- EXPOSE 8086
252
+ The default command launches `retold-stack` against `/media` on port 7777 with hashed filenames disabled. To override (e.g., to enable hashed filenames or change the port):
234
253
 
235
- CMD ["node", "server.js", "/media"]
254
+ ```yaml
255
+ command: ["node", "source/cli/RetoldRemote-Stack-Run.js", "/media", "-p", "7777"]
236
256
  ```
237
257
 
238
- This produces an image under 200MB. Images display directly (no thumbnails), videos play in the browser, and zip/cbz archives use native extraction.
258
+ Remove the `--no-hash` flag to re-enable hashed filenames, or change `/media` if you mounted your media to a different path.
259
+
260
+ ### Image Size Notes
261
+
262
+ - `node:20-slim` base: ~180 MB
263
+ - Full `Dockerfile` (with LibreOffice + Calibre): ~2.5 GB -- Calibre alone is ~1 GB, LibreOffice is ~600 MB
264
+ - `Dockerfile.slim`: ~1.8 GB -- drops both big dependencies
265
+ - Omit `ffmpeg` and `audiowaveform` too if you don't need video/audio processing, for a ~1 GB image
266
+
267
+ ### Child Process Note
268
+
269
+ The stack launcher spawns Ultravisor as a child process using `node` and the resolved `ultravisor` bin path. This works inside Docker without any special configuration -- the child runs in the same container PID namespace and its logs are streamed through the main process's stdout with `[ultravisor]` prefixes.
239
270
 
240
271
  ## Archive Browsing
241
272