@apocaliss92/scrypted-reolink-native 0.2.8 → 0.2.10
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/dist/main.nodejs.js +1 -1
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/baichuan-base.ts +3 -3
- package/src/camera.ts +105 -186
- package/src/debug-options.ts +4 -12
- package/src/intercom.ts +1 -1
- package/src/main.ts +2 -2
- package/src/multiFocal.ts +19 -3
- package/src/stream-utils.ts +129 -98
- package/src/utils.ts +2 -2
package/src/debug-options.ts
CHANGED
|
@@ -10,16 +10,12 @@ export enum DebugLogOption {
|
|
|
10
10
|
DebugRtsp = 'debugRtsp',
|
|
11
11
|
/** Low-level tracing for recording-related commands */
|
|
12
12
|
TraceRecordings = 'traceRecordings',
|
|
13
|
-
/**
|
|
14
|
-
|
|
13
|
+
/** Native stream tracing (stream tx/rx + H264/H265 + param sets) */
|
|
14
|
+
TraceNativeStream = 'traceNativeStream',
|
|
15
15
|
/** Talkback tracing */
|
|
16
16
|
TraceTalk = 'traceTalk',
|
|
17
17
|
/** Event tracing */
|
|
18
18
|
TraceEvents = 'traceEvents',
|
|
19
|
-
/** H.264 debug logs */
|
|
20
|
-
DebugH264 = 'debugH264',
|
|
21
|
-
/** SPS/PPS parameter sets debug logs */
|
|
22
|
-
DebugParamSets = 'debugParamSets',
|
|
23
19
|
}
|
|
24
20
|
|
|
25
21
|
/**
|
|
@@ -30,11 +26,9 @@ export function mapDebugLogToApiOption(option: DebugLogOption): keyof DebugOptio
|
|
|
30
26
|
[DebugLogOption.General]: 'general',
|
|
31
27
|
[DebugLogOption.DebugRtsp]: 'debugRtsp',
|
|
32
28
|
[DebugLogOption.TraceRecordings]: 'traceRecordings',
|
|
33
|
-
[DebugLogOption.
|
|
29
|
+
[DebugLogOption.TraceNativeStream]: 'traceNativeStream',
|
|
34
30
|
[DebugLogOption.TraceTalk]: 'traceTalk',
|
|
35
31
|
[DebugLogOption.TraceEvents]: 'traceEvents',
|
|
36
|
-
[DebugLogOption.DebugH264]: 'debugH264',
|
|
37
|
-
[DebugLogOption.DebugParamSets]: 'debugParamSets',
|
|
38
32
|
};
|
|
39
33
|
return mapping[option];
|
|
40
34
|
}
|
|
@@ -81,11 +75,9 @@ export const DebugLogDisplayNames: Record<DebugLogOption, string> = {
|
|
|
81
75
|
[DebugLogOption.General]: 'General',
|
|
82
76
|
[DebugLogOption.DebugRtsp]: 'RTSP',
|
|
83
77
|
[DebugLogOption.TraceRecordings]: 'Trace recordings',
|
|
84
|
-
[DebugLogOption.
|
|
78
|
+
[DebugLogOption.TraceNativeStream]: 'Trace native stream',
|
|
85
79
|
[DebugLogOption.TraceTalk]: 'Trace talk',
|
|
86
80
|
[DebugLogOption.TraceEvents]: 'Trace events XML',
|
|
87
|
-
[DebugLogOption.DebugH264]: 'H264',
|
|
88
|
-
[DebugLogOption.DebugParamSets]: 'Video param sets',
|
|
89
81
|
};
|
|
90
82
|
|
|
91
83
|
/**
|
package/src/intercom.ts
CHANGED
package/src/main.ts
CHANGED
|
@@ -324,7 +324,7 @@ class ReolinkNativePlugin extends ScryptedDeviceBase implements DeviceProvider,
|
|
|
324
324
|
return;
|
|
325
325
|
}
|
|
326
326
|
} catch (e: any) {
|
|
327
|
-
logger.error('Error in onRequest', e);
|
|
327
|
+
logger.error('Error in onRequest', e?.message || String(e));
|
|
328
328
|
response.send(`Error: ${e.message}`, {
|
|
329
329
|
code: 500,
|
|
330
330
|
});
|
|
@@ -374,7 +374,7 @@ class ReolinkNativePlugin extends ScryptedDeviceBase implements DeviceProvider,
|
|
|
374
374
|
logger.log(`[Thumbnail] Download completed: fileId=${request.fileId}`);
|
|
375
375
|
request.resolve(thumbnail);
|
|
376
376
|
} catch (error) {
|
|
377
|
-
logger.error(`[Thumbnail] Error: fileId=${request.fileId}`, error);
|
|
377
|
+
logger.error(`[Thumbnail] Error: fileId=${request.fileId}`, error?.message || String(error));
|
|
378
378
|
request.reject(error instanceof Error ? error : new Error(String(error)));
|
|
379
379
|
}
|
|
380
380
|
|
package/src/multiFocal.ts
CHANGED
|
@@ -172,12 +172,28 @@ export class ReolinkNativeMultiFocalDevice extends ReolinkCamera implements Sett
|
|
|
172
172
|
throw new Error('Missing device credentials');
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
const outputPath = this.storageSettings.values.diagnosticsOutputPath || process.env.SCRYPTED_PLUGIN_VOLUME || "";
|
|
176
|
+
if (!outputPath) {
|
|
177
|
+
throw new Error('Diagnostics output path is required');
|
|
178
|
+
}
|
|
179
|
+
|
|
175
180
|
const api = await this.ensureClient();
|
|
176
181
|
|
|
177
|
-
const
|
|
182
|
+
const channel = this.storageSettings.values.rtspChannel || 0;
|
|
183
|
+
const durationSeconds = 8;
|
|
184
|
+
const result = await api.runMultifocalDiagnosticsConsecutively({
|
|
185
|
+
logger,
|
|
186
|
+
outDir: outputPath,
|
|
187
|
+
channel,
|
|
188
|
+
durationSeconds,
|
|
189
|
+
rtmpApps: ["bcs"],
|
|
190
|
+
probeFull: true,
|
|
191
|
+
onNvr: !!this.nvrDevice,
|
|
192
|
+
});
|
|
178
193
|
|
|
179
|
-
logger.log(`
|
|
180
|
-
logger.
|
|
194
|
+
logger.log(`Multifocal diagnostics completed successfully. Output directory: ${result.runDir}`);
|
|
195
|
+
logger.log(`Results file: ${result.resultsPath}`);
|
|
196
|
+
logger.log(`Streams directory: ${result.streamsDir}`);
|
|
181
197
|
} catch (e) {
|
|
182
198
|
logger.error('Failed to run NVR diagnostics', e?.message || String(e));
|
|
183
199
|
throw e;
|
package/src/stream-utils.ts
CHANGED
|
@@ -93,6 +93,90 @@ export function parseStreamProfileFromId(id: string | undefined): StreamProfile
|
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
function parseRfcStreamKey(streamKey: string): {
|
|
97
|
+
isComposite: boolean;
|
|
98
|
+
channel?: number;
|
|
99
|
+
variant?: NativeVideoStreamVariant;
|
|
100
|
+
profile?: StreamProfile;
|
|
101
|
+
} {
|
|
102
|
+
const key = String(streamKey ?? '');
|
|
103
|
+
if (!key) {
|
|
104
|
+
throw new Error('parseRfcStreamKey: missing streamKey');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Composite forms supported by the library/server:
|
|
108
|
+
// - composite-main-main (wider-tele)
|
|
109
|
+
// - composite_<profile>
|
|
110
|
+
// - composite_<variant>_<profile>
|
|
111
|
+
// - composite_<variant>_<wider>_<tele>
|
|
112
|
+
if (key.startsWith('composite-')) {
|
|
113
|
+
const parts = key.split('-').filter(Boolean);
|
|
114
|
+
const tele = parts.length >= 3 ? parts[2] : undefined;
|
|
115
|
+
const teleProfile = tele === 'main' || tele === 'sub' || tele === 'ext' ? (tele as StreamProfile) : undefined;
|
|
116
|
+
return { isComposite: true, profile: teleProfile };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (key.startsWith('composite_')) {
|
|
120
|
+
const parts = key.split('_').filter(Boolean);
|
|
121
|
+
// parts[0] === 'composite'
|
|
122
|
+
const maybeVariant = parts.length >= 2 ? parts[1] : undefined;
|
|
123
|
+
const variant =
|
|
124
|
+
maybeVariant === 'default' || maybeVariant === 'autotrack' || maybeVariant === 'telephoto'
|
|
125
|
+
? (maybeVariant as NativeVideoStreamVariant)
|
|
126
|
+
: undefined;
|
|
127
|
+
|
|
128
|
+
// Heuristic: pick last token that looks like a profile as the tele profile.
|
|
129
|
+
const last = parts[parts.length - 1];
|
|
130
|
+
const profile = last === 'main' || last === 'sub' || last === 'ext' ? (last as StreamProfile) : undefined;
|
|
131
|
+
return {
|
|
132
|
+
isComposite: true,
|
|
133
|
+
...(variant && variant !== 'default' ? { variant } : {}),
|
|
134
|
+
...(profile ? { profile } : {}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Non-composite forms supported by the plugin:
|
|
139
|
+
// - channel_<ch>_<profile>
|
|
140
|
+
// - channel_<ch>_<variant>_<profile>
|
|
141
|
+
// - <ch>_<profile>
|
|
142
|
+
// - <ch>_<variant>_<profile>
|
|
143
|
+
const parts = key.split('_').filter(Boolean);
|
|
144
|
+
if (!parts.length) {
|
|
145
|
+
throw new Error(`parseRfcStreamKey: invalid streamKey='${key}'`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let idx = 0;
|
|
149
|
+
if (parts[0] === 'channel') {
|
|
150
|
+
idx = 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const channelStr = parts[idx];
|
|
154
|
+
const channel = channelStr !== undefined ? Number(channelStr) : NaN;
|
|
155
|
+
if (!Number.isFinite(channel)) {
|
|
156
|
+
throw new Error(`parseRfcStreamKey: could not parse channel from streamKey='${key}'`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const tail = parts.slice(idx + 1);
|
|
160
|
+
const last = tail[tail.length - 1];
|
|
161
|
+
const profile = last === 'main' || last === 'sub' || last === 'ext' ? (last as StreamProfile) : undefined;
|
|
162
|
+
|
|
163
|
+
// tail can be:
|
|
164
|
+
// - [profile]
|
|
165
|
+
// - [variant, profile]
|
|
166
|
+
const maybeVariant = tail.length >= 2 ? tail[0] : undefined;
|
|
167
|
+
const variant =
|
|
168
|
+
maybeVariant === 'default' || maybeVariant === 'autotrack' || maybeVariant === 'telephoto'
|
|
169
|
+
? (maybeVariant as NativeVideoStreamVariant)
|
|
170
|
+
: undefined;
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
isComposite: false,
|
|
174
|
+
channel,
|
|
175
|
+
...(variant && variant !== 'default' ? { variant } : {}),
|
|
176
|
+
...(profile ? { profile } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
96
180
|
/**
|
|
97
181
|
* Extract and normalize variant type from stream ID or URL (e.g., "autotrack" from "native_autotrack_main" or "?variant=autotrack")
|
|
98
182
|
* Returns undefined if no variant is present, or "autotrack"/"telephoto" if present
|
|
@@ -163,16 +247,13 @@ export function selectStreamOption(
|
|
|
163
247
|
|
|
164
248
|
export async function createRfc4571MediaObjectFromStreamManager(params: {
|
|
165
249
|
streamManager: StreamManager;
|
|
166
|
-
channel: number;
|
|
167
|
-
profile: StreamProfile;
|
|
168
250
|
streamKey: string;
|
|
169
|
-
variant?: NativeVideoStreamVariant;
|
|
170
251
|
selected: UrlMediaStreamOptions;
|
|
171
252
|
sourceId: string;
|
|
172
253
|
}): Promise<MediaObject> {
|
|
173
|
-
const { streamManager,
|
|
254
|
+
const { streamManager, streamKey, selected, sourceId } = params;
|
|
174
255
|
|
|
175
|
-
const { host, port, sdp, audio, username, password } = await streamManager.
|
|
256
|
+
const { host, port, sdp, audio, username, password } = await streamManager.getRfcServer(streamKey);
|
|
176
257
|
|
|
177
258
|
const { url: _ignoredUrl, ...mso }: any = selected;
|
|
178
259
|
mso.container = 'rtp';
|
|
@@ -203,62 +284,6 @@ export async function createRfc4571MediaObjectFromStreamManager(params: {
|
|
|
203
284
|
});
|
|
204
285
|
}
|
|
205
286
|
|
|
206
|
-
export async function createRfc4571CompositeMediaObjectFromStreamManager(params: {
|
|
207
|
-
streamManager: StreamManager;
|
|
208
|
-
profile: StreamProfile;
|
|
209
|
-
streamKey: string;
|
|
210
|
-
selected: UrlMediaStreamOptions;
|
|
211
|
-
sourceId: string;
|
|
212
|
-
variantType?: NativeVideoStreamVariant;
|
|
213
|
-
}): Promise<MediaObject> {
|
|
214
|
-
const { streamManager, profile, streamKey, selected, sourceId, variantType } = params;
|
|
215
|
-
|
|
216
|
-
// Extract variantType from streamKey if not provided (format: composite_${variantType}_${profile})
|
|
217
|
-
let extractedVariantType = variantType;
|
|
218
|
-
if (!extractedVariantType && streamKey.startsWith('composite_')) {
|
|
219
|
-
const parts = streamKey.split('_');
|
|
220
|
-
if (parts.length >= 3) {
|
|
221
|
-
// Format: composite_${variantType}_${profile}
|
|
222
|
-
const variantPart = parts[1];
|
|
223
|
-
if (variantPart === 'default' || variantPart === 'autotrack' || variantPart === 'telephoto') {
|
|
224
|
-
extractedVariantType = variantPart as NativeVideoStreamVariant;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const { host, port, sdp, audio, username, password } = await streamManager.getRfcCompositeStream(profile, streamKey, extractedVariantType);
|
|
230
|
-
|
|
231
|
-
const { url: _ignoredUrl, ...mso }: any = selected;
|
|
232
|
-
mso.container = 'rtp';
|
|
233
|
-
if (audio) {
|
|
234
|
-
mso.audio ||= {};
|
|
235
|
-
mso.audio.codec = audio.codec;
|
|
236
|
-
mso.audio.sampleRate = audio.sampleRate;
|
|
237
|
-
mso.audio.channels = audio.channels;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Build URL with credentials: tcp://username:password@host:port
|
|
241
|
-
// Keep this consistent with non-composite path (URL object -> JSON string via toJSON()).
|
|
242
|
-
const urlObj = new URL(`tcp://${host}`);
|
|
243
|
-
urlObj.port = port.toString();
|
|
244
|
-
if (username) {
|
|
245
|
-
urlObj.username = username;
|
|
246
|
-
}
|
|
247
|
-
if (password) {
|
|
248
|
-
urlObj.password = password;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const rfc = {
|
|
252
|
-
url: urlObj,
|
|
253
|
-
sdp,
|
|
254
|
-
mediaStreamOptions: mso as ResponseMediaStreamOptions,
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
return await sdk.mediaManager.createMediaObject(Buffer.from(JSON.stringify(rfc)), 'x-scrypted/x-rfc4571', {
|
|
258
|
-
sourceId,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
|
|
262
287
|
type RfcServerInfo = {
|
|
263
288
|
host: string;
|
|
264
289
|
port: number;
|
|
@@ -283,6 +308,27 @@ export class StreamManager {
|
|
|
283
308
|
return this.opts.logger || console;
|
|
284
309
|
}
|
|
285
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Unified RFC4571 server accessor.
|
|
313
|
+
*
|
|
314
|
+
* The streamKey is the single source of truth:
|
|
315
|
+
* - Composite: composite_* (channel-less)
|
|
316
|
+
* - Single channel: channel_<ch>_* or <ch>_*
|
|
317
|
+
*/
|
|
318
|
+
async getRfcServer(streamKey: string, profile?: StreamProfile): Promise<RfcServerInfo> {
|
|
319
|
+
const parsed = parseRfcStreamKey(streamKey);
|
|
320
|
+
const resolvedProfile = profile ?? parsed.profile;
|
|
321
|
+
if (!resolvedProfile) {
|
|
322
|
+
throw new Error(`getRfcServer: could not infer profile from streamKey='${streamKey}'`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return await this.ensureRfcServer(streamKey, resolvedProfile, {
|
|
326
|
+
channel: parsed.isComposite ? undefined : parsed.channel,
|
|
327
|
+
variant: parsed.variant,
|
|
328
|
+
compositeOptions: parsed.isComposite ? this.opts.compositeOptions : undefined,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
286
332
|
private async ensureRfcServer(
|
|
287
333
|
streamKey: string,
|
|
288
334
|
profile: StreamProfile,
|
|
@@ -337,24 +383,16 @@ export class StreamManager {
|
|
|
337
383
|
|
|
338
384
|
const isComposite = options.channel === undefined;
|
|
339
385
|
|
|
386
|
+
// IMPORTANT: do not parse composite profiles here.
|
|
387
|
+
// The library/server derives the composite pairing from the requested id.
|
|
388
|
+
|
|
340
389
|
// For composite streams, we may want two distinct Baichuan sessions (wider + tele)
|
|
341
390
|
// to avoid frame mixing on some firmwares. On BCUDP/battery devices, extra sessions
|
|
342
391
|
// can be harmful; in that case, createStreamClient may return the same underlying client.
|
|
343
392
|
//
|
|
344
|
-
//
|
|
345
|
-
|
|
346
|
-
const
|
|
347
|
-
const compositeTeleChannel = options.compositeOptions?.teleChannel ?? 1;
|
|
348
|
-
const compositeTeleIsVariantOnSameChannel =
|
|
349
|
-
Boolean(options.compositeOptions?.onNvr) || compositeTeleChannel === compositeWiderChannel;
|
|
350
|
-
|
|
351
|
-
const compositeWiderStreamKey = `${compositeWiderChannel}_${profile}`;
|
|
352
|
-
const compositeTeleVariant = compositeTeleIsVariantOnSameChannel
|
|
353
|
-
? (options.variant && options.variant !== 'default' ? options.variant : 'telephoto')
|
|
354
|
-
: undefined;
|
|
355
|
-
const compositeTeleStreamKey = compositeTeleVariant
|
|
356
|
-
? `${compositeTeleChannel}_${compositeTeleVariant}_${profile}`
|
|
357
|
-
: `${compositeTeleChannel}_${profile}`;
|
|
393
|
+
// Use stable per-request keys; include variant for tele to keep sessions distinct.
|
|
394
|
+
const compositeWiderStreamKey = `${streamKey}_wider`;
|
|
395
|
+
const compositeTeleStreamKey = `${streamKey}_tele_${options.variant ?? 'default'}`;
|
|
358
396
|
|
|
359
397
|
// For composite streams, using two distinct Baichuan sessions can avoid frame mixing on some firmwares.
|
|
360
398
|
// However, for UDP/battery devices extra BCUDP sessions can trigger storms; if we detect the same
|
|
@@ -387,11 +425,18 @@ export class StreamManager {
|
|
|
387
425
|
}
|
|
388
426
|
}
|
|
389
427
|
|
|
390
|
-
// For non-composite streams, create a single API client.
|
|
428
|
+
// For non-composite streams, create/reuse a single API client.
|
|
429
|
+
// For NVR/Hub (sharedConnection=true), avoid creating one TCP session per profile
|
|
430
|
+
// (e.g. main+sub would otherwise become two sockets). Group by (channel, variant).
|
|
391
431
|
// For composite streams, base api must be a real lens streamKey (not the composite RFC key).
|
|
432
|
+
const shared = this.opts.sharedConnection ?? false;
|
|
433
|
+
const nonCompositeApiKey = (!isComposite && shared && options.channel !== undefined)
|
|
434
|
+
? `channel_${options.channel}_${options.variant ?? 'default'}`
|
|
435
|
+
: streamKey;
|
|
436
|
+
|
|
392
437
|
const api = isComposite
|
|
393
438
|
? (compositeApis?.widerApi ?? await this.opts.createStreamClient(compositeWiderStreamKey))
|
|
394
|
-
: await this.opts.createStreamClient(
|
|
439
|
+
: await this.opts.createStreamClient(nonCompositeApiKey);
|
|
395
440
|
|
|
396
441
|
const { createRfc4571TcpServer } = await import('@apocaliss92/reolink-baichuan-js');
|
|
397
442
|
|
|
@@ -417,6 +462,7 @@ export class StreamManager {
|
|
|
417
462
|
closeApiOnTeardown,
|
|
418
463
|
username,
|
|
419
464
|
password,
|
|
465
|
+
requestedId: streamKey,
|
|
420
466
|
// Composite can take a bit longer (ffmpeg warmup + first IDR).
|
|
421
467
|
...(isComposite ? { keyframeTimeoutMs: 20_000, idleTeardownMs: 20_000 } : {}),
|
|
422
468
|
...(compositeOptions ? { compositeOptions } : {}),
|
|
@@ -464,10 +510,8 @@ export class StreamManager {
|
|
|
464
510
|
streamKey: string,
|
|
465
511
|
variant?: NativeVideoStreamVariant,
|
|
466
512
|
): Promise<RfcServerInfo> {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
variant,
|
|
470
|
-
});
|
|
513
|
+
// Back-compat wrapper. Prefer getRfcServer(streamKey).
|
|
514
|
+
return await this.ensureRfcServer(streamKey, profile, { channel, variant });
|
|
471
515
|
}
|
|
472
516
|
|
|
473
517
|
async getRfcCompositeStream(
|
|
@@ -475,24 +519,11 @@ export class StreamManager {
|
|
|
475
519
|
streamKey: string,
|
|
476
520
|
variantType?: NativeVideoStreamVariant,
|
|
477
521
|
): Promise<RfcServerInfo> {
|
|
478
|
-
//
|
|
479
|
-
|
|
480
|
-
if (!extractedVariantType && streamKey.startsWith('composite_')) {
|
|
481
|
-
const parts = streamKey.split('_');
|
|
482
|
-
if (parts.length >= 3) {
|
|
483
|
-
// Format: composite_${variantType}_${profile}
|
|
484
|
-
const variantPart = parts[1];
|
|
485
|
-
if (variantPart === 'default' || variantPart === 'autotrack' || variantPart === 'telephoto') {
|
|
486
|
-
extractedVariantType = variantPart as NativeVideoStreamVariant;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// Pass variantType to ensureRfcServer so it can be used when creating the stream client
|
|
492
|
-
// This ensures each variantType gets its own socket
|
|
522
|
+
// Back-compat wrapper. Prefer getRfcServer(streamKey).
|
|
523
|
+
// Pass variantType to ensureRfcServer so it can be used when creating the stream client.
|
|
493
524
|
return await this.ensureRfcServer(streamKey, profile, {
|
|
494
|
-
channel: undefined,
|
|
495
|
-
variant:
|
|
525
|
+
channel: undefined,
|
|
526
|
+
variant: variantType,
|
|
496
527
|
compositeOptions: this.opts.compositeOptions,
|
|
497
528
|
});
|
|
498
529
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1043,7 +1043,7 @@ export async function vodSearchResultsToVideoClips(
|
|
|
1043
1043
|
videoHref = videoUrl;
|
|
1044
1044
|
thumbnailHref = thumbnailUrl;
|
|
1045
1045
|
} catch (e) {
|
|
1046
|
-
logger?.debug('Failed to generate webhook URLs for VOD file', fileName, e);
|
|
1046
|
+
logger?.debug('Failed to generate webhook URLs for VOD file', fileName, e?.message || String(e));
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
1049
|
const clip: VideoClip = {
|
|
@@ -1060,7 +1060,7 @@ export async function vodSearchResultsToVideoClips(
|
|
|
1060
1060
|
|
|
1061
1061
|
clips.push(clip);
|
|
1062
1062
|
} catch (e) {
|
|
1063
|
-
logger?.warn(`Failed to convert VOD file to clip: ${file.name}`, e);
|
|
1063
|
+
logger?.warn(`Failed to convert VOD file to clip: ${file.name}`, e?.message || String(e));
|
|
1064
1064
|
}
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|