retold-remote 0.0.17 → 0.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retold-remote",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "Retold Remote - NAS media browser with gallery views and keyboard navigation",
5
5
  "main": "source/Pict-RetoldRemote-Bundle.js",
6
6
  "bin": {
@@ -40,7 +40,7 @@
40
40
  "orator": "^6.0.4",
41
41
  "orator-serviceserver-restify": "^2.0.9",
42
42
  "parime": "^1.0.3",
43
- "pdf-parse": "^1.1.1",
43
+ "pdf-parse": "^2.4.5",
44
44
  "pict": "^1.0.359",
45
45
  "pict-application": "^1.0.33",
46
46
  "pict-docuserve": "^0.0.32",
@@ -50,14 +50,15 @@
50
50
  "pict-service-commandlineutility": "^1.0.19",
51
51
  "pict-view": "^1.0.67",
52
52
  "retold-content-system": "^1.0.12",
53
- "yauzl": "^3.2.0"
53
+ "ultravisor-beacon": "^0.0.4",
54
+ "yauzl": "^3.2.1"
54
55
  },
55
56
  "optionalDependencies": {
56
57
  "@img/sharp-wasm32": "^0.34.5",
57
58
  "sharp": "^0.34.5"
58
59
  },
59
60
  "devDependencies": {
60
- "puppeteer": "^24.0.0",
61
+ "puppeteer": "^24.40.0",
61
62
  "quackage": "^1.0.65"
62
63
  },
63
64
  "copyFilesSettings": {
@@ -721,12 +721,15 @@ class RetoldRemoteApplication extends libContentEditorApplication
721
721
  */
722
722
  _executeRoute(pRoute, pPath)
723
723
  {
724
+ let tmpRemote = this.pict.AppData.RetoldRemote;
725
+ let tmpActiveMode = tmpRemote.ActiveMode || 'gallery';
726
+
724
727
  switch (pRoute)
725
728
  {
726
729
  case 'browse':
727
730
  {
728
731
  let tmpCurrentPath = (this.pict.AppData.PictFileBrowser && this.pict.AppData.PictFileBrowser.CurrentLocation) || '';
729
- if (pPath !== tmpCurrentPath)
732
+ if (pPath !== tmpCurrentPath || tmpActiveMode !== 'gallery')
730
733
  {
731
734
  this.loadFileList(pPath);
732
735
  }
@@ -735,7 +738,7 @@ class RetoldRemoteApplication extends libContentEditorApplication
735
738
  case 'view':
736
739
  case 'edit':
737
740
  {
738
- if (this.pict.AppData.ContentEditor.CurrentFile !== pPath)
741
+ if (this.pict.AppData.ContentEditor.CurrentFile !== pPath || tmpActiveMode === 'gallery')
739
742
  {
740
743
  this.navigateToFile(pPath);
741
744
  }
@@ -49,6 +49,7 @@ const libRetoldRemoteFileOperationService = require('../server/RetoldRemote-File
49
49
  const libRetoldRemoteAISortService = require('../server/RetoldRemote-AISortService.js');
50
50
  const libRetoldRemoteImageService = require('../server/RetoldRemote-ImageService.js');
51
51
  const libRetoldRemoteUltravisorDispatcher = require('../server/RetoldRemote-UltravisorDispatcher.js');
52
+ const libRetoldRemoteUltravisorBeacon = require('../server/RetoldRemote-UltravisorBeacon.js');
52
53
  const libUrl = require('url');
53
54
 
54
55
  function setupRetoldRemoteServer(pOptions, fCallback)
@@ -88,6 +89,13 @@ function setupRetoldRemoteServer(pOptions, fCallback)
88
89
  if (pOptions.UltravisorURL)
89
90
  {
90
91
  tmpSettings.UltravisorURL = pOptions.UltravisorURL;
92
+
93
+ // Auto-construct ContentAPIURL from the server's own port so beacons
94
+ // know where to download source files from retold-remote.
95
+ if (!pOptions.ContentAPIURL)
96
+ {
97
+ tmpSettings.ContentAPIURL = 'http://localhost:' + pOptions.Port;
98
+ }
91
99
  }
92
100
  if (pOptions.ContentAPIURL)
93
101
  {
@@ -215,6 +223,9 @@ function setupRetoldRemoteServer(pOptions, fCallback)
215
223
  // Set up the Ultravisor dispatcher for offloading heavy processing
216
224
  let tmpDispatcher = new libRetoldRemoteUltravisorDispatcher(tmpFable, {});
217
225
 
226
+ // Set up the Ultravisor beacon for mesh registration
227
+ let tmpBeacon = new libRetoldRemoteUltravisorBeacon(tmpFable, {});
228
+
218
229
  // Wire the dispatcher to services that can offload processing
219
230
  tmpMediaService.setDispatcher(tmpDispatcher);
220
231
  tmpVideoFrameService.setDispatcher(tmpDispatcher);
@@ -2127,7 +2138,7 @@ function setupRetoldRemoteServer(pOptions, fCallback)
2127
2138
  tmpOrator.startService(
2128
2139
  function ()
2129
2140
  {
2130
- return fCallback(null,
2141
+ let tmpServerInfo =
2131
2142
  {
2132
2143
  Fable: tmpFable,
2133
2144
  Orator: tmpOrator,
@@ -2140,8 +2151,41 @@ function setupRetoldRemoteServer(pOptions, fCallback)
2140
2151
  MetadataCache: tmpMetadataCache,
2141
2152
  FileOperationService: tmpFileOperationService,
2142
2153
  UltravisorDispatcher: tmpDispatcher,
2154
+ UltravisorBeacon: tmpBeacon,
2143
2155
  Port: tmpPort
2144
- });
2156
+ };
2157
+
2158
+ // If Ultravisor URL is configured, connect as a beacon
2159
+ if (pOptions.UltravisorURL)
2160
+ {
2161
+ let tmpContentAPIBase = tmpFable.settings.ContentAPIURL || ('http://localhost:' + tmpPort);
2162
+ let tmpContentBaseURL = tmpContentAPIBase + '/content/';
2163
+
2164
+ tmpBeacon.connectBeacon(
2165
+ {
2166
+ ServerURL: pOptions.UltravisorURL,
2167
+ Name: 'retold-remote',
2168
+ ContentPath: tmpContentPath,
2169
+ ContentBaseURL: tmpContentBaseURL,
2170
+ CacheRoot: tmpCacheRoot,
2171
+ StagingPath: tmpCacheRoot || process.cwd(),
2172
+ BindAddresses: [{ IP: '127.0.0.1', Port: tmpPort, Protocol: 'http' }]
2173
+ },
2174
+ (pBeaconError) =>
2175
+ {
2176
+ if (pBeaconError)
2177
+ {
2178
+ tmpFable.log.warn(`Ultravisor Beacon: registration failed (server may not be running): ${pBeaconError.message}`);
2179
+ tmpFable.log.warn('Ultravisor Beacon: server is still running. Beacon will not be active.');
2180
+ }
2181
+ // Non-fatal — return server info regardless
2182
+ return fCallback(null, tmpServerInfo);
2183
+ });
2184
+ }
2185
+ else
2186
+ {
2187
+ return fCallback(null, tmpServerInfo);
2188
+ }
2145
2189
  });
2146
2190
  });
2147
2191
  });
@@ -26,11 +26,37 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
26
26
  this.options.CommandOptions.push(
27
27
  { Name: '--cache-server [url]', Description: 'URL of a remote parime cache server (e.g. http://host:9999).', Default: '' });
28
28
 
29
+ this.options.CommandOptions.push(
30
+ { Name: '-u, --ultravisor [url]', Description: 'Connect to Ultravisor mesh. URL defaults to http://localhost:54321 if omitted.', Default: '' });
31
+
32
+ this.options.CommandOptions.push(
33
+ { Name: '-l, --logfile [path]', Description: 'Write logs to a file (auto-generates timestamped name if path omitted).', Default: '' });
34
+
29
35
  this.addCommand();
30
36
  }
31
37
 
32
38
  onRunAsync(fCallback)
33
39
  {
40
+ // Set up file logging if -l was provided
41
+ let tmpLogfileOpt = this.CommandOptions.logfile;
42
+ if (tmpLogfileOpt)
43
+ {
44
+ let tmpLogfilePath;
45
+ if (typeof tmpLogfileOpt === 'string' && tmpLogfileOpt.length > 0)
46
+ {
47
+ tmpLogfilePath = libPath.resolve(tmpLogfileOpt);
48
+ }
49
+ else
50
+ {
51
+ tmpLogfilePath = libPath.resolve(`retold-remote-${new Date().toISOString().replace(/[:.]/g, '-')}.log`);
52
+ }
53
+ let tmpStreamDef = { loggertype: 'simpleflatfile', level: 'info', path: tmpLogfilePath, outputloglinestoconsole: false, outputobjectstoconsole: false };
54
+ let tmpFileLogger = new this.fable.log._Providers.simpleflatfile(tmpStreamDef, this.fable.log);
55
+ tmpFileLogger.initialize();
56
+ this.fable.log.addLogger(tmpFileLogger, 'info');
57
+ this.log.info(`Logging to file: ${tmpLogfilePath}`);
58
+ }
59
+
34
60
  let tmpContentPath = libPath.resolve(this.ArgumentString || process.cwd());
35
61
 
36
62
  let tmpDistPath = libPath.resolve(__dirname, '..', '..', '..', 'web-application');
@@ -60,6 +86,17 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
60
86
  ? libPath.resolve(this.CommandOptions.cachePath)
61
87
  : null;
62
88
  let tmpCacheServer = this.CommandOptions.cacheServer || null;
89
+ // -u with no URL → true (Commander behavior for [optional]), default to localhost
90
+ let tmpUltravisorOpt = this.CommandOptions.ultravisor;
91
+ let tmpUltravisorURL = null;
92
+ if (tmpUltravisorOpt === true)
93
+ {
94
+ tmpUltravisorURL = 'http://localhost:54321';
95
+ }
96
+ else if (typeof tmpUltravisorOpt === 'string' && tmpUltravisorOpt.length > 0)
97
+ {
98
+ tmpUltravisorURL = tmpUltravisorOpt;
99
+ }
63
100
 
64
101
  tmpSetupServer(
65
102
  {
@@ -68,7 +105,8 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
68
105
  Port: tmpPort,
69
106
  HashedFilenames: tmpHashedFilenames,
70
107
  CacheRoot: tmpCacheRoot,
71
- CacheServer: tmpCacheServer
108
+ CacheServer: tmpCacheServer,
109
+ UltravisorURL: tmpUltravisorURL
72
110
  },
73
111
  function (pError, pServerInfo)
74
112
  {
@@ -85,11 +123,37 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
85
123
  tmpSelf.log.info(` Content: ${tmpContentPath}`);
86
124
  tmpSelf.log.info(` Assets: ${tmpDistPath}`);
87
125
  tmpSelf.log.info(` Browse: http://localhost:${pServerInfo.Port}/`);
126
+ if (pServerInfo.UltravisorBeacon && pServerInfo.UltravisorBeacon.isEnabled())
127
+ {
128
+ tmpSelf.log.info(` Beacon: registered with Ultravisor at ${tmpUltravisorURL}`);
129
+ }
130
+ else if (tmpUltravisorURL)
131
+ {
132
+ tmpSelf.log.info(` Beacon: not connected (Ultravisor may be unreachable)`);
133
+ }
88
134
  tmpSelf.log.info('==========================================================');
89
135
  tmpSelf.log.info('');
90
136
  tmpSelf.log.info(' Press Ctrl+C to stop.');
91
137
  tmpSelf.log.info('');
92
138
 
139
+ // Graceful shutdown: disconnect beacon before exit
140
+ process.on('SIGINT', () =>
141
+ {
142
+ tmpSelf.log.info('');
143
+ tmpSelf.log.info('Shutting down...');
144
+ if (pServerInfo.UltravisorBeacon && pServerInfo.UltravisorBeacon.isEnabled())
145
+ {
146
+ pServerInfo.UltravisorBeacon.disconnectBeacon(() =>
147
+ {
148
+ process.exit(0);
149
+ });
150
+ }
151
+ else
152
+ {
153
+ process.exit(0);
154
+ }
155
+ });
156
+
93
157
  // Intentionally do NOT call fCallback() here.
94
158
  // The server should keep running.
95
159
  });
@@ -136,7 +136,7 @@ class RetoldRemoteAudioWaveformService extends libFableServiceProviderBase
136
136
  {
137
137
  let tmpSelf = this;
138
138
 
139
- // Try Ultravisor dispatch first
139
+ // Try Ultravisor operation trigger first
140
140
  if (this._dispatcher && this._dispatcher.isAvailable())
141
141
  {
142
142
  let tmpRelPath;
@@ -151,25 +151,24 @@ class RetoldRemoteAudioWaveformService extends libFableServiceProviderBase
151
151
 
152
152
  if (tmpRelPath && !tmpRelPath.startsWith('..'))
153
153
  {
154
- let tmpCommand = `ffprobe -v quiet -print_format json -show_format -show_streams "{SourcePath}"`;
155
-
156
- this._dispatcher.dispatchMediaCommand(
154
+ this._dispatcher.triggerOperation('rr-media-probe',
157
155
  {
158
- Command: tmpCommand,
159
- InputPath: tmpRelPath,
160
- AffinityKey: tmpRelPath,
161
- TimeoutMs: 30000
156
+ MediaAddress: '>retold-remote/File/' + tmpRelPath
162
157
  },
163
- (pDispatchError, pResult) =>
158
+ (pTriggerError, pResult) =>
164
159
  {
165
- if (!pDispatchError && pResult && pResult.Outputs && pResult.Outputs.StdOut)
160
+ if (!pTriggerError && pResult && pResult.TaskOutputs)
166
161
  {
167
162
  try
168
163
  {
169
- let tmpData = JSON.parse(pResult.Outputs.StdOut);
170
- let tmpParsed = tmpSelf._parseAudioProbeData(tmpData);
171
- tmpSelf.fable.log.info(`ffprobe (audio) via Ultravisor for ${tmpRelPath}`);
172
- return fCallback(null, tmpParsed);
164
+ let tmpProcessOutput = pResult.TaskOutputs['rr-media-probe-process'];
165
+ if (tmpProcessOutput && tmpProcessOutput.Result)
166
+ {
167
+ let tmpData = JSON.parse(tmpProcessOutput.Result);
168
+ let tmpParsed = tmpSelf._parseAudioProbeData(tmpData);
169
+ tmpSelf.fable.log.info(`ffprobe (audio) via operation trigger for ${tmpRelPath}`);
170
+ return fCallback(null, tmpParsed);
171
+ }
173
172
  }
174
173
  catch (pParseError)
175
174
  {
@@ -192,7 +192,7 @@ class RetoldRemoteEbookService extends libFableServiceProviderBase
192
192
  return fCallback(null, tmpResult);
193
193
  };
194
194
 
195
- // Try Ultravisor dispatch first
195
+ // Try Ultravisor operation trigger first
196
196
  if (this._dispatcher && this._dispatcher.isAvailable())
197
197
  {
198
198
  let tmpRelPath;
@@ -207,24 +207,18 @@ class RetoldRemoteEbookService extends libFableServiceProviderBase
207
207
 
208
208
  if (tmpRelPath && !tmpRelPath.startsWith('..'))
209
209
  {
210
- let tmpCommand = `ebook-convert "{SourcePath}" "{OutputPath}"`;
211
-
212
- this._dispatcher.dispatchMediaCommand(
210
+ this._dispatcher.triggerOperation('rr-ebook-convert',
213
211
  {
214
- Command: tmpCommand,
215
- InputPath: tmpRelPath,
216
- OutputFilename: tmpOutputFilename,
217
- AffinityKey: tmpRelPath,
218
- TimeoutMs: 180000
212
+ EbookAddress: '>retold-remote/File/' + tmpRelPath
219
213
  },
220
- (pDispatchError, pResult) =>
214
+ (pTriggerError, pResult) =>
221
215
  {
222
- if (!pDispatchError && pResult && pResult.OutputBuffer)
216
+ if (!pTriggerError && pResult && pResult.OutputBuffer)
223
217
  {
224
218
  try
225
219
  {
226
220
  libFs.writeFileSync(tmpOutputPath, pResult.OutputBuffer);
227
- tmpSelf.fable.log.info(`Ebook converted via Ultravisor for ${tmpRelPath}`);
221
+ tmpSelf.fable.log.info(`Ebook converted via operation trigger for ${tmpRelPath}`);
228
222
  return _finishConversion(tmpOutputPath, tmpOutputFilename, tmpCacheDir, tmpManifestPath);
229
223
  }
230
224
  catch (pWriteError)
@@ -234,7 +228,7 @@ class RetoldRemoteEbookService extends libFableServiceProviderBase
234
228
  }
235
229
 
236
230
  // Fall through to local processing
237
- tmpSelf.fable.log.info(`Ultravisor dispatch failed for ebook conversion, falling back to local: ${pDispatchError ? pDispatchError.message : 'no output'}`);
231
+ tmpSelf.fable.log.info(`Operation trigger failed for ebook conversion, falling back to local: ${pTriggerError ? pTriggerError.message : 'no output'}`);
238
232
  tmpSelf._convertToEpubLocal(pAbsPath, tmpOutputPath, tmpOutputFilename, tmpCacheDir, tmpManifestPath, pRelPath, fCallback);
239
233
  });
240
234
  return;
@@ -361,7 +361,7 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
361
361
  {
362
362
  let tmpSelf = this;
363
363
 
364
- // Try Ultravisor dispatch first
364
+ // Try Ultravisor operation trigger first
365
365
  if (this._dispatcher && this._dispatcher.isAvailable())
366
366
  {
367
367
  let tmpRelPath;
@@ -376,21 +376,15 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
376
376
 
377
377
  if (tmpRelPath && !tmpRelPath.startsWith('..'))
378
378
  {
379
- let tmpHalfFlag = pFullResolution ? '' : ' -h';
380
- let tmpOutputFilename = libPath.basename(pOutputPath);
381
- let tmpCommand = `dcraw -c -w${tmpHalfFlag} "{SourcePath}" | convert ppm:- jpeg:"{OutputPath}"`;
382
-
383
- this._dispatcher.dispatchMediaCommand(
379
+ this._dispatcher.triggerOperation('rr-image-convert',
384
380
  {
385
- Command: tmpCommand,
386
- InputPath: tmpRelPath,
387
- OutputFilename: tmpOutputFilename,
388
- AffinityKey: tmpRelPath,
389
- TimeoutMs: 180000
381
+ ImageAddress: '>retold-remote/File/' + tmpRelPath,
382
+ Format: 'jpeg',
383
+ Quality: 92
390
384
  },
391
- (pDispatchError, pResult) =>
385
+ (pTriggerError, pResult) =>
392
386
  {
393
- if (!pDispatchError && pResult && pResult.OutputBuffer)
387
+ if (!pTriggerError && pResult && pResult.OutputBuffer)
394
388
  {
395
389
  try
396
390
  {
@@ -400,7 +394,7 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
400
394
  libFs.mkdirSync(tmpDir, { recursive: true });
401
395
  }
402
396
  libFs.writeFileSync(pOutputPath, pResult.OutputBuffer);
403
- tmpSelf.fable.log.info(`Raw conversion via Ultravisor (dcraw) for ${tmpRelPath}`);
397
+ tmpSelf.fable.log.info(`Raw conversion via operation trigger (dcraw) for ${tmpRelPath}`);
404
398
  return fCallback(null);
405
399
  }
406
400
  catch (pWriteError)
@@ -503,7 +497,7 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
503
497
  {
504
498
  let tmpSelf = this;
505
499
 
506
- // Try Ultravisor dispatch first
500
+ // Try Ultravisor operation trigger first
507
501
  if (this._dispatcher && this._dispatcher.isAvailable())
508
502
  {
509
503
  let tmpRelPath;
@@ -518,20 +512,15 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
518
512
 
519
513
  if (tmpRelPath && !tmpRelPath.startsWith('..'))
520
514
  {
521
- let tmpOutputFilename = libPath.basename(pOutputPath);
522
- let tmpCommand = `convert "{SourcePath}" -auto-orient -quality 92 "{OutputPath}"`;
523
-
524
- this._dispatcher.dispatchMediaCommand(
515
+ this._dispatcher.triggerOperation('rr-image-convert',
525
516
  {
526
- Command: tmpCommand,
527
- InputPath: tmpRelPath,
528
- OutputFilename: tmpOutputFilename,
529
- AffinityKey: tmpRelPath,
530
- TimeoutMs: 180000
517
+ ImageAddress: '>retold-remote/File/' + tmpRelPath,
518
+ Format: 'jpeg',
519
+ Quality: 92
531
520
  },
532
- (pDispatchError, pResult) =>
521
+ (pTriggerError, pResult) =>
533
522
  {
534
- if (!pDispatchError && pResult && pResult.OutputBuffer)
523
+ if (!pTriggerError && pResult && pResult.OutputBuffer)
535
524
  {
536
525
  try
537
526
  {
@@ -541,7 +530,7 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
541
530
  libFs.mkdirSync(tmpDir, { recursive: true });
542
531
  }
543
532
  libFs.writeFileSync(pOutputPath, pResult.OutputBuffer);
544
- tmpSelf.fable.log.info(`Raw conversion via Ultravisor (ImageMagick) for ${tmpRelPath}`);
533
+ tmpSelf.fable.log.info(`Raw conversion via operation trigger (ImageMagick) for ${tmpRelPath}`);
545
534
  return fCallback(null);
546
535
  }
547
536
  catch (pWriteError)
@@ -826,19 +815,40 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
826
815
  }
827
816
  });
828
817
  }
829
- else if (this._sharp)
818
+ else if (this._dispatcher && this._dispatcher.isAvailable())
830
819
  {
831
- this._doGeneratePreview(pAbsPath, pAbsPath, pRelPath, tmpMaxDim, tmpCacheKey, tmpOutputFilename, tmpCacheDir, tmpManifestPath, tmpOutputPath, tmpStat, false, fCallback);
820
+ // Prefer Ultravisor dispatch when a beacon is available
821
+ this._doGeneratePreviewWithDispatcher(pAbsPath, pRelPath, tmpMaxDim, tmpCacheKey, tmpOutputFilename, tmpCacheDir, tmpManifestPath, tmpOutputPath, tmpStat, tmpIsRaw,
822
+ (pDispatchError, pResult) =>
823
+ {
824
+ if (!pDispatchError && pResult)
825
+ {
826
+ return fCallback(null, pResult);
827
+ }
828
+ // Dispatch failed — fall through to local tools
829
+ tmpSelf.fable.log.info(`Ultravisor dispatch failed for preview, falling back to local: ${pDispatchError ? pDispatchError.message : 'no result'}`);
830
+ tmpSelf._generatePreviewLocal(pAbsPath, pRelPath, tmpMaxDim, tmpCacheKey, tmpOutputFilename, tmpCacheDir, tmpManifestPath, tmpOutputPath, tmpStat, fCallback);
831
+ });
832
832
  }
833
- else if (this._capabilities.imagemagick)
833
+ else
834
834
  {
835
- // No Sharp available use ImageMagick for standard images too
836
- this._doGeneratePreviewWithImageMagick(pAbsPath, pRelPath, tmpMaxDim, tmpCacheKey, tmpOutputFilename, tmpManifestPath, tmpOutputPath, tmpStat, false, fCallback);
835
+ this._generatePreviewLocal(pAbsPath, pRelPath, tmpMaxDim, tmpCacheKey, tmpOutputFilename, tmpCacheDir, tmpManifestPath, tmpOutputPath, tmpStat, fCallback);
837
836
  }
838
- else if (this._dispatcher && this._dispatcher.isAvailable())
837
+ }
838
+
839
+ /**
840
+ * Generate a preview using local tools (Sharp or ImageMagick).
841
+ * Called when Ultravisor dispatch is unavailable or fails.
842
+ */
843
+ _generatePreviewLocal(pAbsPath, pRelPath, pMaxDim, pCacheKey, pOutputFilename, pCacheDir, pManifestPath, pOutputPath, pStat, fCallback)
844
+ {
845
+ if (this._sharp)
846
+ {
847
+ this._doGeneratePreview(pAbsPath, pAbsPath, pRelPath, pMaxDim, pCacheKey, pOutputFilename, pCacheDir, pManifestPath, pOutputPath, pStat, false, fCallback);
848
+ }
849
+ else if (this._capabilities.imagemagick)
839
850
  {
840
- // No local tools available dispatch to Ultravisor beacon
841
- this._doGeneratePreviewWithDispatcher(pAbsPath, pRelPath, tmpMaxDim, tmpCacheKey, tmpOutputFilename, tmpCacheDir, tmpManifestPath, tmpOutputPath, tmpStat, tmpIsRaw, fCallback);
851
+ this._doGeneratePreviewWithImageMagick(pAbsPath, pRelPath, pMaxDim, pCacheKey, pOutputFilename, pManifestPath, pOutputPath, pStat, false, fCallback);
842
852
  }
843
853
  else
844
854
  {
@@ -1136,24 +1146,19 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
1136
1146
  return fCallback(new Error('File is outside content root.'));
1137
1147
  }
1138
1148
 
1139
- this._dispatcher.dispatchConversion(
1149
+ this._dispatcher.triggerOperation('rr-image-thumbnail',
1140
1150
  {
1141
- Action: 'ImageResize',
1142
- InputPath: tmpRelPath,
1143
- OutputFilename: pOutputFilename,
1151
+ ImageAddress: '>retold-remote/File/' + tmpRelPath,
1144
1152
  Width: pMaxDim,
1145
1153
  Height: pMaxDim,
1146
1154
  Format: 'jpeg',
1147
- Quality: this.options.PreviewQuality || 85,
1148
- AffinityKey: tmpRelPath,
1149
- TimeoutMs: 120000,
1150
- FallbackCommand: `convert "{SourcePath}"[0] -auto-orient -resize ${pMaxDim}x${pMaxDim} -quality ${this.options.PreviewQuality || 85} "{OutputPath}"`
1155
+ Quality: this.options.PreviewQuality || 85
1151
1156
  },
1152
- (pDispatchError, pResult) =>
1157
+ (pTriggerError, pResult) =>
1153
1158
  {
1154
- if (pDispatchError || !pResult || !pResult.OutputBuffer)
1159
+ if (pTriggerError || !pResult || !pResult.OutputBuffer)
1155
1160
  {
1156
- return fCallback(new Error('Ultravisor preview generation failed: ' + (pDispatchError ? pDispatchError.message : 'no output')));
1161
+ return fCallback(new Error('Operation trigger preview generation failed: ' + (pTriggerError ? pTriggerError.message : 'no output')));
1157
1162
  }
1158
1163
 
1159
1164
  try
@@ -1190,7 +1195,7 @@ class RetoldRemoteImageService extends libFableServiceProviderBase
1190
1195
  tmpSelf.fable.log.warn(`Could not write preview manifest: ${pWriteError.message}`);
1191
1196
  }
1192
1197
 
1193
- tmpSelf.fable.log.info(`Generated image preview (Ultravisor): ${pRelPath}`);
1198
+ tmpSelf.fable.log.info(`Generated image preview (operation trigger): ${pRelPath}`);
1194
1199
  return fCallback(null, tmpResult);
1195
1200
  });
1196
1201
  }