@senguoyun/dsh-arkme 0.1.86 → 0.1.87
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/docs/recognized-speaker-directory-backend-handoff-2026-09-28.md +2 -0
- package/docs/recognized-speaker-entry-and-visits.md +2 -0
- package/docs/recognized-speaker-sorting.md +2 -0
- package/docs/speaker-directory-integration-2026-09-30.md +53 -0
- package/lib/client.js +877 -1053
- package/lib/client.js.map +1 -1
- package/lib/index.js +7 -1
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-DfmCJcxH.js → persistent-runtime-0qn1BZ6S.js} +321 -15
- package/lib/types/arkme-service.d.ts +6 -0
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeAvatar.d.ts +2 -1
- package/lib/types/client/ArkmeAvatar.d.ts.map +1 -1
- package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts +3 -30
- package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +1 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/locales/actions-en.d.ts.map +1 -1
- package/lib/types/client/recognized-speaker-directory.d.ts +51 -22
- package/lib/types/client/recognized-speaker-directory.d.ts.map +1 -1
- package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts +2 -4
- package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts.map +1 -1
- package/lib/types/client/recordings/recording-speaker-options-store.d.ts.map +1 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/recording-presence.d.ts +1 -1
- package/lib/types/services/recording-service.d.ts +4 -0
- package/lib/types/services/recording-service.d.ts.map +1 -1
- package/lib/types/services/service.d.ts.map +1 -1
- package/lib/types/services/speaker-directory-service.d.ts +19 -0
- package/lib/types/services/speaker-directory-service.d.ts.map +1 -0
- package/lib/types/services/unmarked-speaker-service.d.ts +2 -0
- package/lib/types/services/unmarked-speaker-service.d.ts.map +1 -1
- package/lib/types/speaker-directory-contract.d.ts +71 -0
- package/lib/types/speaker-directory-contract.d.ts.map +1 -0
- package/lib/types/types.d.ts +1 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
package/lib/client.js
CHANGED
|
@@ -35187,6 +35187,23 @@ Bot 列表加载失败,点击重试|Could not load Bots. Click to retry
|
|
|
35187
35187
|
//#endregion
|
|
35188
35188
|
//#region src/client/locales/actions-en.ts
|
|
35189
35189
|
const actionEnglish = {
|
|
35190
|
+
"加载更多说话人": "Load more speakers",
|
|
35191
|
+
"该分类暂无说话人": "No speakers in this category",
|
|
35192
|
+
"没有匹配的说话人": "No matching speakers",
|
|
35193
|
+
"目录有更新,刷新后查看最新人物。": "The directory has updates. Refresh to see the latest people.",
|
|
35194
|
+
"搜索内容过长,请缩短至 256 字节以内。": "Search text is too long. Keep it within 256 bytes.",
|
|
35195
|
+
"搜索名称或编号": "Search by name or number",
|
|
35196
|
+
"查看状态暂未同步,联网后自动重试。": "View status has not synced. It will retry when online.",
|
|
35197
|
+
"正在加载人物详情…": "Loading person details…",
|
|
35198
|
+
"部分录音仍在整理,人物可能继续更新。": "Some recordings are still being processed. People may continue to update.",
|
|
35199
|
+
"正在更新,当前显示已整理的目录。": "Updating. Showing the available directory.",
|
|
35200
|
+
"更新暂未完成,当前显示上次整理的目录。": "The update has not completed. Showing the previous directory.",
|
|
35201
|
+
"正在整理说话人目录…": "Preparing the speaker directory…",
|
|
35202
|
+
"说话人目录暂不可用,请稍后刷新。": "The speaker directory is unavailable. Please refresh later.",
|
|
35203
|
+
"说话人目录暂不可用,请稍后再试。": "The speaker directory is unavailable. Please try again later.",
|
|
35204
|
+
"声纹状态暂不可用": "Voiceprint status unavailable",
|
|
35205
|
+
"暂时无法更新": "Unable to update",
|
|
35206
|
+
"目录暂不可用": "Directory unavailable",
|
|
35190
35207
|
"发现未发布的草稿": "Unpublished draft found",
|
|
35191
35208
|
"草稿预览": "Draft preview",
|
|
35192
35209
|
"预览草稿": "Preview draft",
|
|
@@ -55159,7 +55176,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55159
55176
|
children: fallback.label || "--"
|
|
55160
55177
|
});
|
|
55161
55178
|
}
|
|
55162
|
-
function ArkmeUserAvatar({ avatarRef, lazy = false, fallback, size = 44, label = "用户头像", senderKind }) {
|
|
55179
|
+
function ArkmeUserAvatar({ avatarRef, lazy = false, fallback, fallbackContent, size = 44, label = "用户头像", senderKind }) {
|
|
55163
55180
|
const normalizedRef = avatarRef?.trim() ?? "";
|
|
55164
55181
|
const container = (0, react$1.useRef)(null);
|
|
55165
55182
|
const imageUrl = useArkmeAvatarImage(normalizedRef, lazy ? container : void 0);
|
|
@@ -55177,7 +55194,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55177
55194
|
}) : fallback?.kind === "phone_default" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PhoneDefaultAvatar, {
|
|
55178
55195
|
fallback,
|
|
55179
55196
|
size
|
|
55180
|
-
}) : senderKind === "bot" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeBotAvatarFallback, { size }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultUserAvatar, { size })
|
|
55197
|
+
}) : fallbackContent ?? (senderKind === "bot" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeBotAvatarFallback, { size }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultUserAvatar, { size }))
|
|
55181
55198
|
});
|
|
55182
55199
|
}
|
|
55183
55200
|
function GroupAvatarMember({ slot, size }) {
|
|
@@ -57229,30 +57246,51 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
57229
57246
|
}
|
|
57230
57247
|
};
|
|
57231
57248
|
//#endregion
|
|
57232
|
-
//#region src/client/recognized-speaker-
|
|
57233
|
-
const
|
|
57234
|
-
|
|
57235
|
-
|
|
57236
|
-
|
|
57237
|
-
|
|
57238
|
-
|
|
57239
|
-
|
|
57249
|
+
//#region src/client/recognized-speaker-directory.ts
|
|
57250
|
+
const loaders = {
|
|
57251
|
+
summary: (input, signal) => callArkme("speaker-directory.summary", input, signal),
|
|
57252
|
+
list: (input, signal) => callArkme("speaker-directory.list", { ...input }, signal),
|
|
57253
|
+
seen: (throughCursor, signal) => callArkme("speaker-directory.seen", { throughCursor }, signal),
|
|
57254
|
+
open: (detailRef, signal) => callArkme("speaker-directory.open", { detailRef }, signal),
|
|
57255
|
+
avatars: (detailRefs, signal) => callArkme("speaker-directory.avatars", { detailRefs }, signal)
|
|
57256
|
+
};
|
|
57257
|
+
var SpeakerReadDeferred = class extends Error {
|
|
57258
|
+
retryAt;
|
|
57259
|
+
constructor(retryAt, cause) {
|
|
57260
|
+
super(cause instanceof Error ? cause.message : "说话人目录暂不可用", { cause });
|
|
57261
|
+
this.retryAt = retryAt;
|
|
57240
57262
|
}
|
|
57241
57263
|
};
|
|
57242
|
-
function
|
|
57243
|
-
|
|
57264
|
+
function directoryErrorCode(error) {
|
|
57265
|
+
const value = error;
|
|
57266
|
+
return value?.body?.code ?? value?.code ?? "";
|
|
57244
57267
|
}
|
|
57245
|
-
|
|
57246
|
-
|
|
57247
|
-
|
|
57248
|
-
|
|
57249
|
-
|
|
57250
|
-
|
|
57251
|
-
|
|
57252
|
-
|
|
57268
|
+
function speakerRetryDelay(error) {
|
|
57269
|
+
if (error instanceof SpeakerReadDeferred) return Math.max(1e3, error.retryAt - Date.now());
|
|
57270
|
+
const value = error;
|
|
57271
|
+
if (directoryErrorCode(error) === "arkme-code-1001" || value?.body?.retryable === false || value?.retryable === false) return void 0;
|
|
57272
|
+
return Math.max(1e3, value?.body?.retryAfterMillis ?? value?.retryAfterMillis ?? 15e3);
|
|
57273
|
+
}
|
|
57274
|
+
const directoryVisible = () => typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
57275
|
+
const normalizeDirectoryQuery = (query) => query.trim().toLowerCase();
|
|
57276
|
+
function directoryQueryValid(query) {
|
|
57277
|
+
return new TextEncoder().encode(normalizeDirectoryQuery(query)).length <= 256;
|
|
57278
|
+
}
|
|
57279
|
+
const queryKey = (query) => JSON.stringify([
|
|
57280
|
+
query.filter,
|
|
57281
|
+
query.sort,
|
|
57282
|
+
normalizeDirectoryQuery(query.query)
|
|
57283
|
+
]);
|
|
57284
|
+
const empty$4 = Object.freeze({});
|
|
57285
|
+
/** Shared summary and immutable same-version pages. No traversal or local new-person inference. */
|
|
57286
|
+
var RecognizedSpeakerDirectory = class {
|
|
57287
|
+
api;
|
|
57288
|
+
now;
|
|
57289
|
+
accounts = /* @__PURE__ */ new Map();
|
|
57253
57290
|
listeners = /* @__PURE__ */ new Set();
|
|
57254
|
-
constructor(
|
|
57255
|
-
this.
|
|
57291
|
+
constructor(api = loaders, now = Date.now) {
|
|
57292
|
+
this.api = api;
|
|
57293
|
+
this.now = now;
|
|
57256
57294
|
}
|
|
57257
57295
|
subscribe = (listener) => {
|
|
57258
57296
|
this.listeners.add(listener);
|
|
@@ -57260,439 +57298,347 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
57260
57298
|
this.listeners.delete(listener);
|
|
57261
57299
|
};
|
|
57262
57300
|
};
|
|
57263
|
-
get = (account) => account === void 0 ? empty$4 : this.
|
|
57264
|
-
emit(
|
|
57265
|
-
this.
|
|
57266
|
-
for (const listener of this.listeners) listener();
|
|
57267
|
-
}
|
|
57268
|
-
read(account) {
|
|
57269
|
-
if (this.records.has(account)) return this.records.get(account);
|
|
57270
|
-
try {
|
|
57271
|
-
const value = JSON.parse(this.getStorage()?.getItem(storageKey$4(account)) ?? "null");
|
|
57272
|
-
if (value !== null && [
|
|
57273
|
-
"known",
|
|
57274
|
-
"current",
|
|
57275
|
-
"pending"
|
|
57276
|
-
].every((key) => {
|
|
57277
|
-
const list = value[key];
|
|
57278
|
-
return Array.isArray(list) && list.length <= 2e4 && list.every((item) => typeof item === "string" && item.length <= 256);
|
|
57279
|
-
})) {
|
|
57280
|
-
this.records.set(account, value);
|
|
57281
|
-
return value;
|
|
57282
|
-
}
|
|
57283
|
-
} catch {}
|
|
57284
|
-
}
|
|
57285
|
-
save(account, value) {
|
|
57286
|
-
this.records.set(account, value);
|
|
57287
|
-
try {
|
|
57288
|
-
this.getStorage()?.setItem(storageKey$4(account), JSON.stringify(value));
|
|
57289
|
-
} catch {}
|
|
57290
|
-
}
|
|
57291
|
-
setTotal(account, total) {
|
|
57292
|
-
if (!Number.isSafeInteger(total) || total < 0) return;
|
|
57293
|
-
const previous = this.get(account);
|
|
57294
|
-
this.emit(account, previous.total === total ? {
|
|
57295
|
-
...previous,
|
|
57296
|
-
total
|
|
57297
|
-
} : {
|
|
57298
|
-
total,
|
|
57299
|
-
checkedAt: 0
|
|
57300
|
-
});
|
|
57301
|
+
get = (account) => account === void 0 ? empty$4 : this.accounts.get(account)?.snapshot ?? empty$4;
|
|
57302
|
+
emit() {
|
|
57303
|
+
this.listeners.forEach((listener) => listener());
|
|
57301
57304
|
}
|
|
57302
|
-
|
|
57303
|
-
|
|
57304
|
-
|
|
57305
|
-
|
|
57306
|
-
|
|
57307
|
-
|
|
57305
|
+
account(key) {
|
|
57306
|
+
let found = this.accounts.get(key);
|
|
57307
|
+
if (!found) {
|
|
57308
|
+
found = {
|
|
57309
|
+
controller: new AbortController(),
|
|
57310
|
+
snapshot: empty$4,
|
|
57311
|
+
summaryAt: 0,
|
|
57312
|
+
retryAt: 0,
|
|
57313
|
+
failures: 0,
|
|
57314
|
+
flights: /* @__PURE__ */ new Map(),
|
|
57315
|
+
lists: /* @__PURE__ */ new Map(),
|
|
57316
|
+
pendingSeen: /* @__PURE__ */ new Set(),
|
|
57317
|
+
confirmedSeen: /* @__PURE__ */ new Set(),
|
|
57318
|
+
expiredSeen: /* @__PURE__ */ new Set(),
|
|
57319
|
+
revision: 0
|
|
57320
|
+
};
|
|
57321
|
+
this.accounts.set(key, found);
|
|
57322
|
+
}
|
|
57323
|
+
return found;
|
|
57308
57324
|
}
|
|
57309
|
-
|
|
57310
|
-
|
|
57311
|
-
if (
|
|
57312
|
-
|
|
57313
|
-
|
|
57314
|
-
|
|
57315
|
-
|
|
57316
|
-
|
|
57317
|
-
|
|
57318
|
-
|
|
57325
|
+
current(account, value) {
|
|
57326
|
+
value.controller.signal.throwIfAborted();
|
|
57327
|
+
if (this.accounts.get(account) !== value) throw new DOMException("账号已切换", "AbortError");
|
|
57328
|
+
}
|
|
57329
|
+
async request(account, key, load) {
|
|
57330
|
+
const value = this.account(account);
|
|
57331
|
+
this.current(account, value);
|
|
57332
|
+
key = `${value.revision}:${key}`;
|
|
57333
|
+
const pending = value.flights.get(key);
|
|
57334
|
+
if (pending) return pending;
|
|
57335
|
+
if (this.now() < value.retryAt) throw new SpeakerReadDeferred(value.retryAt, /* @__PURE__ */ new Error("请求较频繁或网络暂不可用,请稍后重试"));
|
|
57336
|
+
const promise = Promise.resolve().then(() => load(value.controller.signal)).then((result) => {
|
|
57337
|
+
this.current(account, value);
|
|
57338
|
+
value.failures = 0;
|
|
57339
|
+
return result;
|
|
57340
|
+
}).catch((error) => {
|
|
57341
|
+
this.current(account, value);
|
|
57342
|
+
const delay = speakerRetryDelay(error);
|
|
57343
|
+
if (delay !== void 0) {
|
|
57344
|
+
value.failures += 1;
|
|
57345
|
+
value.retryAt = this.now() + Math.max(delay, Math.min(3e5, 1e3 * 2 ** Math.min(8, value.failures)));
|
|
57346
|
+
throw new SpeakerReadDeferred(value.retryAt, error);
|
|
57347
|
+
}
|
|
57348
|
+
throw error;
|
|
57349
|
+
}).finally(() => {
|
|
57350
|
+
if (value.flights.get(key) === promise) value.flights.delete(key);
|
|
57319
57351
|
});
|
|
57352
|
+
value.flights.set(key, promise);
|
|
57353
|
+
return promise;
|
|
57320
57354
|
}
|
|
57321
|
-
|
|
57322
|
-
const
|
|
57323
|
-
if (
|
|
57324
|
-
|
|
57325
|
-
|
|
57355
|
+
async summary(account, force = false) {
|
|
57356
|
+
const state = this.account(account), cached = state.snapshot.summary, revision = state.revision;
|
|
57357
|
+
if (!force && cached && (cached.state === "disabled" || this.now() < state.summaryAt)) return cached;
|
|
57358
|
+
try {
|
|
57359
|
+
const result = await this.request(account, "summary", (signal) => this.api.summary(cached && cached.snapshotVersion ? {
|
|
57360
|
+
snapshotVersion: cached.snapshotVersion,
|
|
57361
|
+
seenVersion: cached.seenVersion
|
|
57362
|
+
} : {}, signal));
|
|
57363
|
+
this.current(account, state);
|
|
57364
|
+
if (revision !== state.revision) return this.summary(account, force);
|
|
57365
|
+
state.snapshot = { summary: result };
|
|
57366
|
+
state.summaryAt = this.now() + (result.retryAfterMs > 0 ? result.retryAfterMs : 3e4);
|
|
57367
|
+
this.emit();
|
|
57368
|
+
return result;
|
|
57369
|
+
} catch (error) {
|
|
57370
|
+
this.current(account, state);
|
|
57371
|
+
state.snapshot = {
|
|
57372
|
+
...state.snapshot,
|
|
57373
|
+
error: error instanceof Error ? error.message : "目录暂不可用"
|
|
57374
|
+
};
|
|
57375
|
+
this.emit();
|
|
57376
|
+
throw error;
|
|
57326
57377
|
}
|
|
57327
|
-
const current = [.../* @__PURE__ */ new Set([...marked, ...candidates.map((candidate) => `u:${candidate.identityKey}`)])];
|
|
57328
|
-
const previous = this.read(account);
|
|
57329
|
-
const known = new Set(previous?.known ?? []);
|
|
57330
|
-
const currentSet = new Set(current);
|
|
57331
|
-
const removed = previous?.current.some((key) => !currentSet.has(key)) ?? false;
|
|
57332
|
-
const additions = previous === void 0 || removed ? [] : current.filter((key) => !known.has(key));
|
|
57333
|
-
const pending = viewed ? [] : [.../* @__PURE__ */ new Set([...(previous?.pending ?? []).filter((key) => currentSet.has(key)), ...additions])];
|
|
57334
|
-
current.forEach((key) => known.add(key));
|
|
57335
|
-
const record = known.size > 2e4 ? {
|
|
57336
|
-
known: current,
|
|
57337
|
-
current,
|
|
57338
|
-
pending: []
|
|
57339
|
-
} : {
|
|
57340
|
-
known: [...known],
|
|
57341
|
-
current,
|
|
57342
|
-
pending
|
|
57343
|
-
};
|
|
57344
|
-
this.save(account, record);
|
|
57345
|
-
this.emit(account, {
|
|
57346
|
-
total: current.length,
|
|
57347
|
-
newCount: record.pending.length,
|
|
57348
|
-
checkedAt: Date.now()
|
|
57349
|
-
});
|
|
57350
|
-
}
|
|
57351
|
-
clearSession() {
|
|
57352
|
-
this.snapshots.clear();
|
|
57353
|
-
this.records.clear();
|
|
57354
|
-
for (const listener of this.listeners) listener();
|
|
57355
|
-
}
|
|
57356
|
-
};
|
|
57357
|
-
const recognizedSpeakerTracker = new RecognizedSpeakerTracker();
|
|
57358
|
-
let activeAccount$1 = "";
|
|
57359
|
-
arkmeAuthStore.subscribe(() => {
|
|
57360
|
-
const auth = arkmeAuthStore.getSnapshot().auth;
|
|
57361
|
-
const next = auth?.status === "authenticated" ? `${auth.environment}:${auth.userId}` : "";
|
|
57362
|
-
if (next !== activeAccount$1) {
|
|
57363
|
-
activeAccount$1 = next;
|
|
57364
|
-
recognizedSpeakerTracker.clearSession();
|
|
57365
|
-
}
|
|
57366
|
-
});
|
|
57367
|
-
//#endregion
|
|
57368
|
-
//#region src/client/recognized-speaker-order.ts
|
|
57369
|
-
const preferenceKey$3 = (accountKey) => `dsh-arkme:recognized-speaker-order:v1:${accountKey}`;
|
|
57370
|
-
function browserStorage$1() {
|
|
57371
|
-
try {
|
|
57372
|
-
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
57373
|
-
} catch {
|
|
57374
|
-
return;
|
|
57375
57378
|
}
|
|
57376
|
-
|
|
57377
|
-
|
|
57378
|
-
try {
|
|
57379
|
-
return storage?.getItem(preferenceKey$3(accountKey)) === "recent" ? "recent" : "frequent";
|
|
57380
|
-
} catch {
|
|
57381
|
-
return "frequent";
|
|
57379
|
+
peek(account, query) {
|
|
57380
|
+
return this.accounts.get(account)?.lists.get(queryKey(query));
|
|
57382
57381
|
}
|
|
57383
|
-
|
|
57384
|
-
|
|
57385
|
-
|
|
57386
|
-
|
|
57387
|
-
|
|
57388
|
-
|
|
57389
|
-
|
|
57390
|
-
|
|
57391
|
-
|
|
57392
|
-
|
|
57393
|
-
|
|
57394
|
-
|
|
57395
|
-
|
|
57396
|
-
|
|
57397
|
-
|
|
57398
|
-
|
|
57399
|
-
|
|
57400
|
-
* traversal complete. No audio or per-speaker detail is loaded here.
|
|
57401
|
-
*/
|
|
57402
|
-
async function loadSpeakerCandidateSnapshot(loadPage, signal, onProgress) {
|
|
57403
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
57404
|
-
const rows = /* @__PURE__ */ new Map();
|
|
57405
|
-
const cursors = /* @__PURE__ */ new Set();
|
|
57406
|
-
let cursor = "";
|
|
57407
|
-
let snapshot = {
|
|
57382
|
+
async first(account, query, signal, force = false) {
|
|
57383
|
+
if (!directoryQueryValid(query.query)) throw new Error("搜索内容过长,请缩短至 256 字节以内");
|
|
57384
|
+
signal.throwIfAborted();
|
|
57385
|
+
const state = this.account(account), revision = state.revision;
|
|
57386
|
+
const summary = await this.summary(account, force);
|
|
57387
|
+
signal.throwIfAborted();
|
|
57388
|
+
const key = queryKey(query), cached = state.lists.get(key);
|
|
57389
|
+
if (!force && cached && cached.snapshotVersion === summary.snapshotVersion && !state.expiredSeen.has(cached.throughCursor)) return cached;
|
|
57390
|
+
const input = {
|
|
57391
|
+
...query,
|
|
57392
|
+
query: normalizeDirectoryQuery(query.query),
|
|
57393
|
+
cursor: "",
|
|
57394
|
+
snapshotVersion: summary.snapshotVersion,
|
|
57395
|
+
limit: 50
|
|
57396
|
+
};
|
|
57397
|
+
const page = summary.state === "disabled" || summary.coverage !== "complete" ? {
|
|
57398
|
+
...summary,
|
|
57408
57399
|
items: [],
|
|
57409
|
-
|
|
57410
|
-
|
|
57400
|
+
hasMore: false,
|
|
57401
|
+
nextCursor: "",
|
|
57402
|
+
throughCursor: ""
|
|
57403
|
+
} : await this.request(account, `list:${JSON.stringify(input)}`, (inner) => this.api.list(input, inner));
|
|
57404
|
+
signal.throwIfAborted();
|
|
57405
|
+
this.current(account, state);
|
|
57406
|
+
if (revision !== state.revision) throw new DOMException("目录已更新", "AbortError");
|
|
57407
|
+
if (page.state === "snapshot_expired") {
|
|
57408
|
+
state.summaryAt = 0;
|
|
57409
|
+
state.lists.delete(key);
|
|
57410
|
+
if (page.retryAfterMs > 0) {
|
|
57411
|
+
state.retryAt = Math.max(state.retryAt, this.now() + page.retryAfterMs);
|
|
57412
|
+
throw new SpeakerReadDeferred(state.retryAt, /* @__PURE__ */ new Error("目录正在更新,请稍后重试"));
|
|
57413
|
+
}
|
|
57414
|
+
if (force) throw new Error("目录正在更新,请稍后刷新");
|
|
57415
|
+
return this.first(account, query, signal, true);
|
|
57416
|
+
}
|
|
57417
|
+
if (page.state === "disabled") {
|
|
57418
|
+
state.snapshot = { summary: {
|
|
57419
|
+
...summary,
|
|
57420
|
+
state: "disabled"
|
|
57421
|
+
} };
|
|
57422
|
+
this.emit();
|
|
57423
|
+
}
|
|
57424
|
+
const result = {
|
|
57425
|
+
...page,
|
|
57426
|
+
query: {
|
|
57427
|
+
...query,
|
|
57428
|
+
query: input.query
|
|
57429
|
+
},
|
|
57430
|
+
requestedCursors: [""]
|
|
57411
57431
|
};
|
|
57412
|
-
|
|
57413
|
-
|
|
57414
|
-
|
|
57415
|
-
|
|
57416
|
-
if (page.section !== "unmarked-speakers") throw new Error("未标记说话人列表响应无效");
|
|
57417
|
-
if (page.cursorStale) {
|
|
57418
|
-
snapshot = {
|
|
57419
|
-
items: [],
|
|
57420
|
-
complete: false,
|
|
57421
|
-
projectionState: "stale"
|
|
57422
|
-
};
|
|
57423
|
-
onProgress(snapshot);
|
|
57424
|
-
if (attempt === 0) break;
|
|
57425
|
-
return snapshot;
|
|
57426
|
-
}
|
|
57427
|
-
for (const item of page.items) if (item.kind === "unmarked-speaker" && rows.size < 2e3) rows.set(item.candidateRef, item);
|
|
57428
|
-
snapshot = {
|
|
57429
|
-
items: [...rows.values()],
|
|
57430
|
-
complete: !page.hasMore && page.coverage !== "partial" && (page.projectionState === void 0 || page.projectionState === "fresh"),
|
|
57431
|
-
projectionState: page.projectionState
|
|
57432
|
-
};
|
|
57433
|
-
onProgress(snapshot);
|
|
57434
|
-
if (!page.hasMore || rows.size >= 2e3 || page.projectionState !== void 0 && page.projectionState !== "fresh") return snapshot;
|
|
57435
|
-
const next = page.nextCursor ?? "";
|
|
57436
|
-
if (next === "" || cursors.has(next)) return snapshot;
|
|
57437
|
-
cursors.add(next);
|
|
57438
|
-
cursor = next;
|
|
57439
|
-
if (pageIndex === 39) return snapshot;
|
|
57432
|
+
if (page.coverage === "complete" && page.state !== "disabled") {
|
|
57433
|
+
state.lists.delete(key);
|
|
57434
|
+
state.lists.set(key, result);
|
|
57435
|
+
while (state.lists.size > 12) state.lists.delete(state.lists.keys().next().value);
|
|
57440
57436
|
}
|
|
57437
|
+
return result;
|
|
57441
57438
|
}
|
|
57442
|
-
|
|
57443
|
-
items: [],
|
|
57444
|
-
complete: false,
|
|
57445
|
-
projectionState: "stale"
|
|
57446
|
-
};
|
|
57447
|
-
}
|
|
57448
|
-
//#endregion
|
|
57449
|
-
//#region src/client/recognized-speaker-directory.ts
|
|
57450
|
-
const readSpeakerOptions = (signal) => callArkme("recordings.speaker.options", {}, signal);
|
|
57451
|
-
const readSpeakerPresence = (signal) => callArkme("recordings.speaker.presence", {}, signal);
|
|
57452
|
-
const readSpeakerPage = (cursor, signal) => callArkme("directory.list", {
|
|
57453
|
-
section: "unmarked-speakers",
|
|
57454
|
-
limit: 50,
|
|
57455
|
-
...cursor === "" ? {} : { cursor }
|
|
57456
|
-
}, signal);
|
|
57457
|
-
var SpeakerReadDeferred = class extends Error {
|
|
57458
|
-
retryAt;
|
|
57459
|
-
constructor(retryAt, cause) {
|
|
57460
|
-
super(cause instanceof Error ? cause.message : "说话人列表暂时无法加载", { cause });
|
|
57461
|
-
this.retryAt = retryAt;
|
|
57462
|
-
}
|
|
57463
|
-
};
|
|
57464
|
-
function speakerRetryDelay(error) {
|
|
57465
|
-
return error instanceof SpeakerReadDeferred ? Math.max(1e3, error.retryAt - Date.now()) : void 0;
|
|
57466
|
-
}
|
|
57467
|
-
/** Per-account shared read. A short release grace lets entry -> list hand off the same
|
|
57468
|
-
* request; leaving both cancels it. A late/aborted response can never update the cache.
|
|
57469
|
-
*/
|
|
57470
|
-
var SharedRead = class {
|
|
57471
|
-
ttl;
|
|
57472
|
-
load;
|
|
57473
|
-
now;
|
|
57474
|
-
value;
|
|
57475
|
-
freshUntil = 0;
|
|
57476
|
-
retryAt = 0;
|
|
57477
|
-
failures = 0;
|
|
57478
|
-
error;
|
|
57479
|
-
pending;
|
|
57480
|
-
listeners = /* @__PURE__ */ new Set();
|
|
57481
|
-
releaseTimer;
|
|
57482
|
-
constructor(ttl, load, now) {
|
|
57483
|
-
this.ttl = ttl;
|
|
57484
|
-
this.load = load;
|
|
57485
|
-
this.now = now;
|
|
57486
|
-
}
|
|
57487
|
-
read(signal, progress = () => {}) {
|
|
57439
|
+
async more(account, previous, signal) {
|
|
57488
57440
|
signal.throwIfAborted();
|
|
57489
|
-
if (
|
|
57490
|
-
|
|
57491
|
-
if (
|
|
57492
|
-
|
|
57493
|
-
|
|
57494
|
-
|
|
57495
|
-
|
|
57496
|
-
|
|
57497
|
-
|
|
57498
|
-
|
|
57499
|
-
|
|
57500
|
-
|
|
57501
|
-
|
|
57502
|
-
|
|
57503
|
-
|
|
57504
|
-
|
|
57505
|
-
|
|
57506
|
-
|
|
57507
|
-
|
|
57508
|
-
|
|
57509
|
-
|
|
57510
|
-
|
|
57511
|
-
|
|
57512
|
-
|
|
57513
|
-
|
|
57514
|
-
|
|
57515
|
-
|
|
57516
|
-
|
|
57517
|
-
|
|
57518
|
-
|
|
57519
|
-
|
|
57520
|
-
|
|
57521
|
-
|
|
57522
|
-
|
|
57523
|
-
|
|
57441
|
+
if (!previous.hasMore) return previous;
|
|
57442
|
+
const state = this.account(account), revision = state.revision;
|
|
57443
|
+
if (!state.lists.has(queryKey(previous.query))) return this.first(account, previous.query, signal, true);
|
|
57444
|
+
const input = {
|
|
57445
|
+
...previous.query,
|
|
57446
|
+
limit: 50,
|
|
57447
|
+
cursor: previous.nextCursor,
|
|
57448
|
+
snapshotVersion: previous.snapshotVersion
|
|
57449
|
+
};
|
|
57450
|
+
const page = await this.request(account, `list:${JSON.stringify(input)}`, (inner) => this.api.list(input, inner));
|
|
57451
|
+
signal.throwIfAborted();
|
|
57452
|
+
this.current(account, state);
|
|
57453
|
+
if (revision !== state.revision) throw new DOMException("目录已更新", "AbortError");
|
|
57454
|
+
if (page.state === "snapshot_expired") {
|
|
57455
|
+
state.lists.delete(queryKey(previous.query));
|
|
57456
|
+
state.summaryAt = 0;
|
|
57457
|
+
if (page.retryAfterMs > 0) {
|
|
57458
|
+
state.retryAt = Math.max(state.retryAt, this.now() + page.retryAfterMs);
|
|
57459
|
+
throw new SpeakerReadDeferred(state.retryAt, /* @__PURE__ */ new Error("目录正在更新,请稍后刷新"));
|
|
57460
|
+
}
|
|
57461
|
+
return this.first(account, previous.query, signal, true);
|
|
57462
|
+
}
|
|
57463
|
+
if (page.state === "disabled") {
|
|
57464
|
+
const summary = state.snapshot.summary;
|
|
57465
|
+
if (summary) {
|
|
57466
|
+
state.snapshot = { summary: {
|
|
57467
|
+
...summary,
|
|
57468
|
+
state: "disabled"
|
|
57469
|
+
} };
|
|
57470
|
+
this.emit();
|
|
57471
|
+
}
|
|
57472
|
+
return {
|
|
57473
|
+
...previous,
|
|
57474
|
+
state: "disabled",
|
|
57475
|
+
hasMore: false
|
|
57524
57476
|
};
|
|
57525
57477
|
}
|
|
57526
|
-
|
|
57527
|
-
|
|
57528
|
-
|
|
57529
|
-
|
|
57530
|
-
|
|
57531
|
-
|
|
57532
|
-
|
|
57533
|
-
|
|
57534
|
-
|
|
57535
|
-
|
|
57536
|
-
|
|
57537
|
-
}, 250);
|
|
57538
|
-
};
|
|
57539
|
-
const abort = () => {
|
|
57540
|
-
cleanup();
|
|
57541
|
-
reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
57542
|
-
};
|
|
57543
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
57544
|
-
pending.promise.then((value) => {
|
|
57545
|
-
cleanup();
|
|
57546
|
-
if (!signal.aborted) resolve(value);
|
|
57547
|
-
}, (error) => {
|
|
57548
|
-
cleanup();
|
|
57549
|
-
if (!signal.aborted) reject(error);
|
|
57550
|
-
});
|
|
57551
|
-
});
|
|
57552
|
-
}
|
|
57553
|
-
invalidate() {
|
|
57554
|
-
clearTimeout(this.releaseTimer);
|
|
57555
|
-
this.pending?.controller.abort();
|
|
57556
|
-
this.pending = void 0;
|
|
57557
|
-
this.freshUntil = 0;
|
|
57558
|
-
}
|
|
57559
|
-
dispose() {
|
|
57560
|
-
this.invalidate();
|
|
57561
|
-
this.listeners.clear();
|
|
57562
|
-
this.value = void 0;
|
|
57563
|
-
}
|
|
57564
|
-
};
|
|
57565
|
-
function pause(milliseconds, signal) {
|
|
57566
|
-
if (milliseconds <= 0) return Promise.resolve();
|
|
57567
|
-
return new Promise((resolve, reject) => {
|
|
57568
|
-
const abort = () => {
|
|
57569
|
-
clearTimeout(timer);
|
|
57570
|
-
reject(signal.reason);
|
|
57478
|
+
if (page.snapshotVersion !== previous.snapshotVersion || page.coverage !== "complete" || page.hasMore && (page.nextCursor === previous.nextCursor || previous.requestedCursors.includes(page.nextCursor))) throw new Error("目录版本已变化,请刷新列表");
|
|
57479
|
+
const keys = new Set(previous.items.map((item) => item.personKey));
|
|
57480
|
+
const result = {
|
|
57481
|
+
...page,
|
|
57482
|
+
query: previous.query,
|
|
57483
|
+
requestedCursors: [...previous.requestedCursors, previous.nextCursor],
|
|
57484
|
+
items: [...previous.items, ...page.items.filter((item) => {
|
|
57485
|
+
if (keys.has(item.personKey)) return false;
|
|
57486
|
+
keys.add(item.personKey);
|
|
57487
|
+
return true;
|
|
57488
|
+
})]
|
|
57571
57489
|
};
|
|
57572
|
-
|
|
57573
|
-
|
|
57574
|
-
resolve();
|
|
57575
|
-
}, milliseconds);
|
|
57576
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
57577
|
-
if (signal.aborted) abort();
|
|
57578
|
-
});
|
|
57579
|
-
}
|
|
57580
|
-
var RecognizedSpeakerDirectory = class {
|
|
57581
|
-
loaders;
|
|
57582
|
-
pageGapMs;
|
|
57583
|
-
now;
|
|
57584
|
-
accounts = /* @__PURE__ */ new Map();
|
|
57585
|
-
constructor(loaders = {
|
|
57586
|
-
marked: readSpeakerOptions,
|
|
57587
|
-
page: readSpeakerPage,
|
|
57588
|
-
presence: readSpeakerPresence
|
|
57589
|
-
}, pageGapMs = 750, now = Date.now) {
|
|
57590
|
-
this.loaders = loaders;
|
|
57591
|
-
this.pageGapMs = pageGapMs;
|
|
57592
|
-
this.now = now;
|
|
57490
|
+
state.lists.set(queryKey(previous.query), result);
|
|
57491
|
+
return result;
|
|
57593
57492
|
}
|
|
57594
|
-
|
|
57595
|
-
|
|
57596
|
-
|
|
57597
|
-
|
|
57598
|
-
|
|
57599
|
-
|
|
57600
|
-
state =
|
|
57601
|
-
|
|
57602
|
-
|
|
57603
|
-
|
|
57604
|
-
|
|
57605
|
-
|
|
57606
|
-
|
|
57607
|
-
|
|
57608
|
-
|
|
57609
|
-
|
|
57610
|
-
|
|
57611
|
-
|
|
57612
|
-
|
|
57613
|
-
|
|
57614
|
-
|
|
57615
|
-
|
|
57616
|
-
|
|
57617
|
-
|
|
57618
|
-
|
|
57619
|
-
|
|
57620
|
-
} else if (page.projectionState === void 0 || page.projectionState === "fresh") pages.set(cursor, page);
|
|
57621
|
-
return page;
|
|
57622
|
-
}, signal, (snapshot) => {
|
|
57623
|
-
const first = pages.get("");
|
|
57624
|
-
total = first?.coverage !== "partial" ? first?.total : void 0;
|
|
57625
|
-
if (!state.candidates.value?.complete || snapshot.complete) emit({
|
|
57626
|
-
...snapshot,
|
|
57627
|
-
total
|
|
57628
|
-
});
|
|
57629
|
-
});
|
|
57630
|
-
completed = result.complete;
|
|
57631
|
-
if (!result.complete) {
|
|
57632
|
-
if (!state.candidates.value?.complete) emit({
|
|
57633
|
-
...result,
|
|
57634
|
-
total
|
|
57635
|
-
});
|
|
57636
|
-
throw new Error("说话人列表尚未完整,请稍后重试");
|
|
57493
|
+
async confirmDisplayed(account, list) {
|
|
57494
|
+
if (!directoryVisible() || list.query.filter !== "all" || list.query.query !== "" || list.coverage !== "complete" || ![
|
|
57495
|
+
"fresh",
|
|
57496
|
+
"stale",
|
|
57497
|
+
"failed"
|
|
57498
|
+
].includes(list.state) || !list.throughCursor) return;
|
|
57499
|
+
const state = this.account(account);
|
|
57500
|
+
if (state.confirmedSeen.has(list.throughCursor) || state.expiredSeen.has(list.throughCursor) || state.snapshot.summary?.state === "disabled") return;
|
|
57501
|
+
state.pendingSeen.add(list.throughCursor);
|
|
57502
|
+
await this.flushSeen(account);
|
|
57503
|
+
}
|
|
57504
|
+
async flushSeen(account) {
|
|
57505
|
+
const state = this.account(account);
|
|
57506
|
+
if (!directoryVisible() || state.snapshot.summary?.state === "disabled") return;
|
|
57507
|
+
for (const cursor of state.pendingSeen) {
|
|
57508
|
+
let result;
|
|
57509
|
+
try {
|
|
57510
|
+
result = await this.request(account, `seen:${cursor}`, (signal) => this.api.seen(cursor, signal));
|
|
57511
|
+
} catch (error) {
|
|
57512
|
+
if (directoryErrorCode(error) === "arkme-code-1001") {
|
|
57513
|
+
state.pendingSeen.delete(cursor);
|
|
57514
|
+
state.expiredSeen.add(cursor);
|
|
57515
|
+
state.lists.clear();
|
|
57516
|
+
state.summaryAt = 0;
|
|
57517
|
+
this.emit();
|
|
57518
|
+
continue;
|
|
57637
57519
|
}
|
|
57638
|
-
|
|
57639
|
-
|
|
57640
|
-
|
|
57641
|
-
|
|
57642
|
-
|
|
57643
|
-
|
|
57644
|
-
|
|
57645
|
-
|
|
57646
|
-
|
|
57647
|
-
|
|
57648
|
-
|
|
57649
|
-
|
|
57650
|
-
|
|
57651
|
-
|
|
57520
|
+
throw error;
|
|
57521
|
+
}
|
|
57522
|
+
this.current(account, state);
|
|
57523
|
+
if (result.success) {
|
|
57524
|
+
state.pendingSeen.delete(cursor);
|
|
57525
|
+
state.confirmedSeen.add(cursor);
|
|
57526
|
+
await Promise.allSettled([...state.flights.entries()].filter(([key]) => key.endsWith(":summary")).map(([, promise]) => promise));
|
|
57527
|
+
await this.summary(account, true);
|
|
57528
|
+
} else if (result.state === "snapshot_expired") {
|
|
57529
|
+
state.pendingSeen.delete(cursor);
|
|
57530
|
+
state.expiredSeen.add(cursor);
|
|
57531
|
+
state.lists.clear();
|
|
57532
|
+
state.summaryAt = 0;
|
|
57533
|
+
if (result.retryAfterMs > 0) state.retryAt = Math.max(state.retryAt, this.now() + result.retryAfterMs);
|
|
57534
|
+
this.emit();
|
|
57535
|
+
} else {
|
|
57536
|
+
state.pendingSeen.clear();
|
|
57537
|
+
if (state.snapshot.summary) state.snapshot = { summary: {
|
|
57538
|
+
...state.snapshot.summary,
|
|
57539
|
+
state: "disabled"
|
|
57540
|
+
} };
|
|
57541
|
+
this.emit();
|
|
57542
|
+
return;
|
|
57543
|
+
}
|
|
57544
|
+
}
|
|
57652
57545
|
}
|
|
57653
|
-
|
|
57654
|
-
return this.accounts.get(account)?.
|
|
57546
|
+
hasPendingSeen(account) {
|
|
57547
|
+
return (this.accounts.get(account)?.pendingSeen.size ?? 0) > 0;
|
|
57655
57548
|
}
|
|
57656
|
-
|
|
57657
|
-
return this.
|
|
57549
|
+
needsReload(account, list) {
|
|
57550
|
+
return this.accounts.get(account)?.expiredSeen.has(list.throughCursor) === true;
|
|
57658
57551
|
}
|
|
57659
|
-
|
|
57660
|
-
|
|
57552
|
+
open(account, ref, signal) {
|
|
57553
|
+
signal.throwIfAborted();
|
|
57554
|
+
return this.request(account, `open:${ref}`, (inner) => this.api.open(ref, inner)).then((value) => {
|
|
57555
|
+
signal.throwIfAborted();
|
|
57556
|
+
return value;
|
|
57557
|
+
});
|
|
57661
57558
|
}
|
|
57662
|
-
|
|
57663
|
-
this.account(account)
|
|
57664
|
-
|
|
57559
|
+
async avatars(account, detailRefs, signal) {
|
|
57560
|
+
const state = this.account(account);
|
|
57561
|
+
const result = await this.api.avatars(detailRefs, AbortSignal.any([state.controller.signal, signal]));
|
|
57562
|
+
signal.throwIfAborted();
|
|
57563
|
+
this.current(account, state);
|
|
57564
|
+
return result;
|
|
57665
57565
|
}
|
|
57666
|
-
|
|
57667
|
-
|
|
57566
|
+
/** Visible consumers share one lightweight summary request, including online/focus recovery. */
|
|
57567
|
+
watch(account, changed = () => {}) {
|
|
57568
|
+
let disposed = false, busy = false, timer;
|
|
57569
|
+
const run = async () => {
|
|
57570
|
+
if (disposed || busy || !directoryVisible()) return;
|
|
57571
|
+
busy = true;
|
|
57572
|
+
let delay = 3e4;
|
|
57573
|
+
try {
|
|
57574
|
+
const summary = await this.summary(account);
|
|
57575
|
+
if (summary.state === "disabled") {
|
|
57576
|
+
changed();
|
|
57577
|
+
return;
|
|
57578
|
+
}
|
|
57579
|
+
await this.flushSeen(account);
|
|
57580
|
+
changed();
|
|
57581
|
+
delay = summary.retryAfterMs > 0 ? summary.retryAfterMs : 3e4;
|
|
57582
|
+
} catch (error) {
|
|
57583
|
+
delay = speakerRetryDelay(error) ?? 0;
|
|
57584
|
+
changed();
|
|
57585
|
+
} finally {
|
|
57586
|
+
busy = false;
|
|
57587
|
+
if (!disposed && delay > 0 && this.get(account).summary?.state !== "disabled") {
|
|
57588
|
+
clearTimeout(timer);
|
|
57589
|
+
timer = setTimeout(() => {
|
|
57590
|
+
run();
|
|
57591
|
+
}, Math.max(1e3, delay));
|
|
57592
|
+
}
|
|
57593
|
+
}
|
|
57594
|
+
};
|
|
57595
|
+
const wake = () => {
|
|
57596
|
+
if (directoryVisible()) {
|
|
57597
|
+
const value = this.account(account);
|
|
57598
|
+
value.summaryAt = 0;
|
|
57599
|
+
run();
|
|
57600
|
+
}
|
|
57601
|
+
};
|
|
57602
|
+
run();
|
|
57603
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", wake);
|
|
57604
|
+
if (typeof window !== "undefined") {
|
|
57605
|
+
window.addEventListener("online", wake);
|
|
57606
|
+
window.addEventListener("focus", wake);
|
|
57607
|
+
}
|
|
57608
|
+
return () => {
|
|
57609
|
+
disposed = true;
|
|
57610
|
+
clearTimeout(timer);
|
|
57611
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", wake);
|
|
57612
|
+
if (typeof window !== "undefined") {
|
|
57613
|
+
window.removeEventListener("online", wake);
|
|
57614
|
+
window.removeEventListener("focus", wake);
|
|
57615
|
+
}
|
|
57616
|
+
};
|
|
57668
57617
|
}
|
|
57669
57618
|
invalidate(account) {
|
|
57670
57619
|
const state = this.accounts.get(account);
|
|
57671
|
-
if (state
|
|
57672
|
-
state.
|
|
57673
|
-
state.
|
|
57674
|
-
state.
|
|
57675
|
-
|
|
57620
|
+
if (!state) return;
|
|
57621
|
+
state.revision += 1;
|
|
57622
|
+
state.summaryAt = 0;
|
|
57623
|
+
state.lists.clear();
|
|
57624
|
+
this.emit();
|
|
57676
57625
|
}
|
|
57677
57626
|
clear() {
|
|
57678
|
-
|
|
57679
|
-
state.marked.dispose();
|
|
57680
|
-
state.presence.dispose();
|
|
57681
|
-
state.candidates.dispose();
|
|
57682
|
-
}
|
|
57627
|
+
this.accounts.forEach((state) => state.controller.abort());
|
|
57683
57628
|
this.accounts.clear();
|
|
57629
|
+
this.emit();
|
|
57684
57630
|
}
|
|
57685
57631
|
};
|
|
57686
57632
|
const recognizedSpeakerDirectory = new RecognizedSpeakerDirectory();
|
|
57687
|
-
const
|
|
57633
|
+
const currentAccount$1 = () => {
|
|
57688
57634
|
const auth = arkmeAuthStore.getSnapshot().auth;
|
|
57689
57635
|
return auth?.status === "authenticated" ? `${auth.environment}:${auth.userId}` : "";
|
|
57690
57636
|
};
|
|
57691
|
-
let
|
|
57637
|
+
let account$1 = currentAccount$1();
|
|
57692
57638
|
arkmeAuthStore.subscribe(() => {
|
|
57693
|
-
const next =
|
|
57694
|
-
if (next !==
|
|
57695
|
-
|
|
57639
|
+
const next = currentAccount$1();
|
|
57640
|
+
if (next !== account$1) {
|
|
57641
|
+
account$1 = next;
|
|
57696
57642
|
recognizedSpeakerDirectory.clear();
|
|
57697
57643
|
}
|
|
57698
57644
|
});
|
|
@@ -57752,10 +57698,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
57752
57698
|
throw error;
|
|
57753
57699
|
} finally {
|
|
57754
57700
|
if (context.current()) {
|
|
57755
|
-
if (binding.account !== void 0)
|
|
57756
|
-
recognizedSpeakerTracker.uncertain(binding.account);
|
|
57757
|
-
recognizedSpeakerDirectory.invalidate(binding.account);
|
|
57758
|
-
}
|
|
57701
|
+
if (binding.account !== void 0) recognizedSpeakerDirectory.invalidate(binding.account);
|
|
57759
57702
|
recordingSpeakerOptions.reset();
|
|
57760
57703
|
recordingSpeakerOptions.invalidate();
|
|
57761
57704
|
recordingSpeakerItemContexts.reset((candidateKey) => candidateKey === key || !recordingSpeakerItemContexts.get(candidateKey).mutating);
|
|
@@ -126905,11 +126848,11 @@ body[data-ds-dark-theme] .arkme-mention-all-avatar [data-arkme-theme-image="dark
|
|
|
126905
126848
|
}
|
|
126906
126849
|
const MAX_PREFERENCE = 4096;
|
|
126907
126850
|
const PADDING = 12;
|
|
126908
|
-
const preferenceKey$
|
|
126851
|
+
const preferenceKey$3 = (account) => `dsh-arkme:calendar-height:v1:${encodeURIComponent(account)}`;
|
|
126909
126852
|
function readCalendarHeight(account) {
|
|
126910
126853
|
if (!account) return void 0;
|
|
126911
126854
|
try {
|
|
126912
|
-
const value = Number(localStorage.getItem(preferenceKey$
|
|
126855
|
+
const value = Number(localStorage.getItem(preferenceKey$3(account)));
|
|
126913
126856
|
return Number.isFinite(value) && value >= 360 && value <= MAX_PREFERENCE ? value : void 0;
|
|
126914
126857
|
} catch {
|
|
126915
126858
|
return;
|
|
@@ -126918,7 +126861,7 @@ body[data-ds-dark-theme] .arkme-mention-all-avatar [data-arkme-theme-image="dark
|
|
|
126918
126861
|
function writeCalendarHeight(account, height) {
|
|
126919
126862
|
if (!account || !Number.isFinite(height)) return;
|
|
126920
126863
|
try {
|
|
126921
|
-
localStorage.setItem(preferenceKey$
|
|
126864
|
+
localStorage.setItem(preferenceKey$3(account), String(Math.round(Math.max(360, Math.min(MAX_PREFERENCE, height)))));
|
|
126922
126865
|
} catch {}
|
|
126923
126866
|
}
|
|
126924
126867
|
function calendarPopoverLayout(anchor, width, height, preferred) {
|
|
@@ -138440,14 +138383,14 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
138440
138383
|
return;
|
|
138441
138384
|
}
|
|
138442
138385
|
}
|
|
138443
|
-
function preferenceKey$
|
|
138386
|
+
function preferenceKey$2(userId) {
|
|
138444
138387
|
return Number.isSafeInteger(userId) && (userId ?? 0) > 0 ? `${STORAGE_KEY_PREFIX$3}${String(userId)}` : void 0;
|
|
138445
138388
|
}
|
|
138446
138389
|
function isSelfTopicSort(value) {
|
|
138447
138390
|
return value === "latest" || value === "most" || value === "custom";
|
|
138448
138391
|
}
|
|
138449
138392
|
function readSelfTopicSortPreference(userId, storage) {
|
|
138450
|
-
const key = preferenceKey$
|
|
138393
|
+
const key = preferenceKey$2(userId);
|
|
138451
138394
|
const target = preferenceStorage$1(storage);
|
|
138452
138395
|
if (key === void 0 || target === void 0) return DEFAULT_SELF_TOPIC_SORT;
|
|
138453
138396
|
try {
|
|
@@ -138458,7 +138401,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
138458
138401
|
}
|
|
138459
138402
|
}
|
|
138460
138403
|
function writeSelfTopicSortPreference(userId, sort, storage) {
|
|
138461
|
-
const key = preferenceKey$
|
|
138404
|
+
const key = preferenceKey$2(userId);
|
|
138462
138405
|
const target = preferenceStorage$1(storage);
|
|
138463
138406
|
if (key === void 0 || target === void 0) return;
|
|
138464
138407
|
try {
|
|
@@ -143882,7 +143825,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
143882
143825
|
return;
|
|
143883
143826
|
}
|
|
143884
143827
|
}
|
|
143885
|
-
function preferenceKey(userId) {
|
|
143828
|
+
function preferenceKey$1(userId) {
|
|
143886
143829
|
return Number.isSafeInteger(userId) && (userId ?? 0) > 0 ? `${STORAGE_KEY_PREFIX$2}user:${String(userId)}` : `${STORAGE_KEY_PREFIX$2}anonymous`;
|
|
143887
143830
|
}
|
|
143888
143831
|
function isMarketplaceSort(value) {
|
|
@@ -143892,7 +143835,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
143892
143835
|
const target = preferenceStorage(storage);
|
|
143893
143836
|
if (target === void 0) return DEFAULT_MARKETPLACE_SORT;
|
|
143894
143837
|
try {
|
|
143895
|
-
const value = target.getItem(preferenceKey(userId));
|
|
143838
|
+
const value = target.getItem(preferenceKey$1(userId));
|
|
143896
143839
|
return isMarketplaceSort(value) ? value : DEFAULT_MARKETPLACE_SORT;
|
|
143897
143840
|
} catch {
|
|
143898
143841
|
return DEFAULT_MARKETPLACE_SORT;
|
|
@@ -143902,7 +143845,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
143902
143845
|
const target = preferenceStorage(storage);
|
|
143903
143846
|
if (target === void 0) return;
|
|
143904
143847
|
try {
|
|
143905
|
-
target.setItem(preferenceKey(userId), sort);
|
|
143848
|
+
target.setItem(preferenceKey$1(userId), sort);
|
|
143906
143849
|
} catch {}
|
|
143907
143850
|
}
|
|
143908
143851
|
//#endregion
|
|
@@ -155445,7 +155388,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155445
155388
|
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
|
155446
155389
|
*/
|
|
155447
155390
|
const useInternalLayoutEffect = canUseDom() ? react.useLayoutEffect : react.useEffect;
|
|
155448
|
-
const useLayoutEffect$
|
|
155391
|
+
const useLayoutEffect$25 = (callback, deps) => {
|
|
155449
155392
|
const firstMountRef = react.useRef(true);
|
|
155450
155393
|
useInternalLayoutEffect(() => {
|
|
155451
155394
|
return callback(firstMountRef.current);
|
|
@@ -155489,7 +155432,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155489
155432
|
function useControlledState(defaultStateValue, value) {
|
|
155490
155433
|
const [innerValue, setInnerValue] = (0, react.useState)(defaultStateValue);
|
|
155491
155434
|
const mergedValue = value !== void 0 ? value : innerValue;
|
|
155492
|
-
useLayoutEffect$
|
|
155435
|
+
useLayoutEffect$25((mount) => {
|
|
155493
155436
|
if (!mount) setInnerValue(value);
|
|
155494
155437
|
}, [value]);
|
|
155495
155438
|
return [mergedValue, setInnerValue];
|
|
@@ -155552,7 +155495,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155552
155495
|
};
|
|
155553
155496
|
//#endregion
|
|
155554
155497
|
//#region node_modules/@rc-component/util/es/hooks/useMemo.js
|
|
155555
|
-
function useMemo$
|
|
155498
|
+
function useMemo$36(getValue, condition, shouldUpdate) {
|
|
155556
155499
|
const cacheRef = react.useRef({});
|
|
155557
155500
|
if (!("value" in cacheRef.current) || shouldUpdate(cacheRef.current.condition, condition)) {
|
|
155558
155501
|
cacheRef.current.value = getValue();
|
|
@@ -155665,7 +155608,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155665
155608
|
};
|
|
155666
155609
|
};
|
|
155667
155610
|
const useComposeRef = (...refs) => {
|
|
155668
|
-
return useMemo$
|
|
155611
|
+
return useMemo$36(() => composeRef(...refs), refs, (prev, next) => prev.length !== next.length || prev.every((ref, i) => ref !== next[i]));
|
|
155669
155612
|
};
|
|
155670
155613
|
const supportRef = (nodeOrComponent) => {
|
|
155671
155614
|
if (!nodeOrComponent) return false;
|
|
@@ -156555,13 +156498,13 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
156555
156498
|
ele.parentElement?.removeChild(ele);
|
|
156556
156499
|
appendedRef.current = false;
|
|
156557
156500
|
}
|
|
156558
|
-
useLayoutEffect$
|
|
156501
|
+
useLayoutEffect$25(() => {
|
|
156559
156502
|
if (render) if (queueCreate) queueCreate(append);
|
|
156560
156503
|
else append();
|
|
156561
156504
|
else cleanup();
|
|
156562
156505
|
return cleanup;
|
|
156563
156506
|
}, [render]);
|
|
156564
|
-
useLayoutEffect$
|
|
156507
|
+
useLayoutEffect$25(() => {
|
|
156565
156508
|
if (queue.length) {
|
|
156566
156509
|
queue.forEach((appendFn) => appendFn());
|
|
156567
156510
|
setQueue(EMPTY_LIST);
|
|
@@ -156587,7 +156530,7 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
156587
156530
|
uuid$1 += 1;
|
|
156588
156531
|
return `${UNIQUE_ID}_${uuid$1}`;
|
|
156589
156532
|
});
|
|
156590
|
-
useLayoutEffect$
|
|
156533
|
+
useLayoutEffect$25(() => {
|
|
156591
156534
|
if (mergedLock) {
|
|
156592
156535
|
const scrollbarSize = getTargetScrollBarSize(document.body).width;
|
|
156593
156536
|
updateCSS(`
|
|
@@ -157530,7 +157473,7 @@ html body {
|
|
|
157530
157473
|
]);
|
|
157531
157474
|
const getPopupContainerNeedParams = getPopupContainer?.length > 0;
|
|
157532
157475
|
const [show, setShow] = react.useState(!getPopupContainer || !getPopupContainerNeedParams);
|
|
157533
|
-
useLayoutEffect$
|
|
157476
|
+
useLayoutEffect$25(() => {
|
|
157534
157477
|
if (!show && getPopupContainerNeedParams && target) setShow(true);
|
|
157535
157478
|
}, [
|
|
157536
157479
|
show,
|
|
@@ -158082,8 +158025,8 @@ html body {
|
|
|
158082
158025
|
ready: false
|
|
158083
158026
|
}));
|
|
158084
158027
|
};
|
|
158085
|
-
useLayoutEffect$
|
|
158086
|
-
useLayoutEffect$
|
|
158028
|
+
useLayoutEffect$25(resetReady, [placement]);
|
|
158029
|
+
useLayoutEffect$25(() => {
|
|
158087
158030
|
if (!open) resetReady();
|
|
158088
158031
|
}, [open]);
|
|
158089
158032
|
return [
|
|
@@ -158127,7 +158070,7 @@ html body {
|
|
|
158127
158070
|
//#endregion
|
|
158128
158071
|
//#region node_modules/@rc-component/trigger/es/hooks/useWatch.js
|
|
158129
158072
|
function useWatch(open, target, popup, onAlign, onScroll) {
|
|
158130
|
-
useLayoutEffect$
|
|
158073
|
+
useLayoutEffect$25(() => {
|
|
158131
158074
|
if (open && target && popup) {
|
|
158132
158075
|
const targetElement = target;
|
|
158133
158076
|
const popupElement = popup;
|
|
@@ -158282,7 +158225,7 @@ html body {
|
|
|
158282
158225
|
id,
|
|
158283
158226
|
onEsc
|
|
158284
158227
|
}));
|
|
158285
|
-
useLayoutEffect$
|
|
158228
|
+
useLayoutEffect$25(() => {
|
|
158286
158229
|
if (uniqueContext && unique && targetEle && !openUncontrolled && !parentContext) if (mergedOpen) uniqueContext.show(getUniqueOptions(mouseEnterDelay), isOpen);
|
|
158287
158230
|
else uniqueContext.hide(mouseLeaveDelay);
|
|
158288
158231
|
}, [mergedOpen, targetEle]);
|
|
@@ -158318,7 +158261,7 @@ html body {
|
|
|
158318
158261
|
if (top) triggerOpen(false);
|
|
158319
158262
|
}
|
|
158320
158263
|
const [inMotion, setInMotion] = react.useState(false);
|
|
158321
|
-
useLayoutEffect$
|
|
158264
|
+
useLayoutEffect$25((firstMount) => {
|
|
158322
158265
|
if (!firstMount || mergedOpen) setInMotion(true);
|
|
158323
158266
|
}, [mergedOpen]);
|
|
158324
158267
|
const [motionPrepareResolve, setMotionPrepareResolve] = react.useState(null);
|
|
@@ -158337,10 +158280,10 @@ html body {
|
|
|
158337
158280
|
if (openRef.current && alignPoint && clickToHide) triggerOpen(false);
|
|
158338
158281
|
};
|
|
158339
158282
|
useWatch(mergedOpen, targetEle, popupEle, triggerAlign, onScroll);
|
|
158340
|
-
useLayoutEffect$
|
|
158283
|
+
useLayoutEffect$25(() => {
|
|
158341
158284
|
triggerAlign();
|
|
158342
158285
|
}, [mousePos, popupPlacement]);
|
|
158343
|
-
useLayoutEffect$
|
|
158286
|
+
useLayoutEffect$25(() => {
|
|
158344
158287
|
if (mergedOpen && !builtinPlacements?.[popupPlacement]) triggerAlign();
|
|
158345
158288
|
}, [JSON.stringify(popupAlign)]);
|
|
158346
158289
|
const alignedClassName = react.useMemo(() => {
|
|
@@ -158380,7 +158323,7 @@ html body {
|
|
|
158380
158323
|
syncTargetSize();
|
|
158381
158324
|
setMotionPrepareResolve(() => resolve);
|
|
158382
158325
|
});
|
|
158383
|
-
useLayoutEffect$
|
|
158326
|
+
useLayoutEffect$25(() => {
|
|
158384
158327
|
if (motionPrepareResolve) {
|
|
158385
158328
|
onAlign();
|
|
158386
158329
|
motionPrepareResolve();
|
|
@@ -158587,7 +158530,7 @@ html body {
|
|
|
158587
158530
|
}
|
|
158588
158531
|
function useTarget(target, open, gap, scrollIntoViewOptions, inlineMode, placeholderRef) {
|
|
158589
158532
|
const [targetElement, setTargetElement] = (0, react.useState)(void 0);
|
|
158590
|
-
useLayoutEffect$
|
|
158533
|
+
useLayoutEffect$25(() => {
|
|
158591
158534
|
const nextElement = typeof target === "function" ? target() : target;
|
|
158592
158535
|
setTargetElement(nextElement || null);
|
|
158593
158536
|
});
|
|
@@ -158617,7 +158560,7 @@ html body {
|
|
|
158617
158560
|
} else setPosInfo(null);
|
|
158618
158561
|
});
|
|
158619
158562
|
const getGapOffset = (index) => (Array.isArray(gap?.offset) ? gap?.offset[index] : gap?.offset) ?? 6;
|
|
158620
|
-
useLayoutEffect$
|
|
158563
|
+
useLayoutEffect$25(() => {
|
|
158621
158564
|
updatePos();
|
|
158622
158565
|
window.addEventListener("resize", updatePos);
|
|
158623
158566
|
window.addEventListener("scroll", updatePos);
|
|
@@ -158907,7 +158850,7 @@ html body {
|
|
|
158907
158850
|
const mergedOpen = mergedCurrent < 0 || mergedCurrent >= steps.length ? false : internalOpen ?? true;
|
|
158908
158851
|
const [hasOpened, setHasOpened] = react.useState(mergedOpen);
|
|
158909
158852
|
const openRef = react.useRef(mergedOpen);
|
|
158910
|
-
useLayoutEffect$
|
|
158853
|
+
useLayoutEffect$25(() => {
|
|
158911
158854
|
if (mergedOpen) {
|
|
158912
158855
|
if (!openRef.current) setMergedCurrent(0);
|
|
158913
158856
|
setHasOpened(true);
|
|
@@ -158924,7 +158867,7 @@ html body {
|
|
|
158924
158867
|
const mergedPlacement = getPlacement(targetElement, placement, stepPlacement);
|
|
158925
158868
|
const mergedArrow = targetElement ? typeof stepArrow === "undefined" ? arrow : stepArrow : false;
|
|
158926
158869
|
const arrowPointAtCenter = typeof mergedArrow === "object" ? mergedArrow.pointAtCenter : false;
|
|
158927
|
-
useLayoutEffect$
|
|
158870
|
+
useLayoutEffect$25(() => {
|
|
158928
158871
|
triggerRef.current?.forceAlign();
|
|
158929
158872
|
}, [arrowPointAtCenter, mergedCurrent]);
|
|
158930
158873
|
const onInternalChange = (nextCurrent) => {
|
|
@@ -158962,7 +158905,7 @@ html body {
|
|
|
158962
158905
|
return;
|
|
158963
158906
|
}
|
|
158964
158907
|
});
|
|
158965
|
-
useLayoutEffect$
|
|
158908
|
+
useLayoutEffect$25(() => {
|
|
158966
158909
|
if (!mergedOpen) return;
|
|
158967
158910
|
window.addEventListener("keydown", keyboardHandler);
|
|
158968
158911
|
return () => {
|
|
@@ -166447,7 +166390,7 @@ html body {
|
|
|
166447
166390
|
//#endregion
|
|
166448
166391
|
//#region src/client/self-topic-expansion-preference.ts
|
|
166449
166392
|
const EMPTY$1 = /* @__PURE__ */ new Set();
|
|
166450
|
-
function browserStorage() {
|
|
166393
|
+
function browserStorage$1() {
|
|
166451
166394
|
try {
|
|
166452
166395
|
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
166453
166396
|
} catch {
|
|
@@ -166466,7 +166409,7 @@ html body {
|
|
|
166466
166409
|
storage;
|
|
166467
166410
|
value;
|
|
166468
166411
|
listeners = /* @__PURE__ */ new Set();
|
|
166469
|
-
constructor(key, storage = browserStorage()) {
|
|
166412
|
+
constructor(key, storage = browserStorage$1()) {
|
|
166470
166413
|
this.key = key;
|
|
166471
166414
|
this.storage = storage;
|
|
166472
166415
|
this.value = this.read();
|
|
@@ -179003,73 +178946,19 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
179003
178946
|
const p$2 = e$36;
|
|
179004
178947
|
//#endregion
|
|
179005
178948
|
//#region src/client/recordings/RecognizedSpeakerEntry.tsx
|
|
179006
|
-
function RecognizedSpeakerEntry({ accountKey, active, onOpen, style,
|
|
178949
|
+
function RecognizedSpeakerEntry({ accountKey, active, onOpen, style, directory = recognizedSpeakerDirectory }) {
|
|
179007
178950
|
useArkmeLocale();
|
|
179008
|
-
const
|
|
179009
|
-
marked: readMarked,
|
|
179010
|
-
page: readPage,
|
|
179011
|
-
presence: readSpeakerPresence
|
|
179012
|
-
}, 0)), [
|
|
179013
|
-
providedDirectory,
|
|
179014
|
-
readMarked,
|
|
179015
|
-
readPage
|
|
179016
|
-
]);
|
|
179017
|
-
const snapshot = (0, react$1.useSyncExternalStore)(recognizedSpeakerTracker.subscribe, () => recognizedSpeakerTracker.get(accountKey), () => recognizedSpeakerTracker.get(accountKey));
|
|
178951
|
+
const snapshot = (0, react$1.useSyncExternalStore)(directory.subscribe, () => directory.get(accountKey), () => directory.get(accountKey));
|
|
179018
178952
|
(0, react$1.useEffect)(() => {
|
|
179019
|
-
if (
|
|
179020
|
-
const controller = new AbortController();
|
|
179021
|
-
let busy = false;
|
|
179022
|
-
let retryTimer;
|
|
179023
|
-
const refresh = async () => {
|
|
179024
|
-
if (busy || controller.signal.aborted || typeof document !== "undefined" && document.visibilityState === "hidden") return;
|
|
179025
|
-
busy = true;
|
|
179026
|
-
try {
|
|
179027
|
-
let marked;
|
|
179028
|
-
const updateTotal = () => {
|
|
179029
|
-
const value = directory.peekCandidates(accountKey);
|
|
179030
|
-
if (marked !== void 0 && value?.total !== void 0 && !controller.signal.aborted) recognizedSpeakerTracker.setTotal(accountKey, markedSpeakerKeys(marked).length + value.total);
|
|
179031
|
-
};
|
|
179032
|
-
const [, result] = await Promise.all([directory.readMarked(accountKey, controller.signal).then((value) => {
|
|
179033
|
-
marked = value;
|
|
179034
|
-
updateTotal();
|
|
179035
|
-
}), directory.readCandidates(accountKey, controller.signal, updateTotal)]);
|
|
179036
|
-
if (controller.signal.aborted) return;
|
|
179037
|
-
if (result.complete && marked !== void 0) recognizedSpeakerTracker.observe(accountKey, marked, result.items);
|
|
179038
|
-
else recognizedSpeakerTracker.uncertain(accountKey);
|
|
179039
|
-
} catch (error) {
|
|
179040
|
-
if (!controller.signal.aborted) {
|
|
179041
|
-
recognizedSpeakerTracker.uncertain(accountKey);
|
|
179042
|
-
const delay = speakerRetryDelay(error);
|
|
179043
|
-
if (delay !== void 0) {
|
|
179044
|
-
clearTimeout(retryTimer);
|
|
179045
|
-
retryTimer = setTimeout(() => {
|
|
179046
|
-
refresh();
|
|
179047
|
-
}, delay);
|
|
179048
|
-
}
|
|
179049
|
-
}
|
|
179050
|
-
} finally {
|
|
179051
|
-
busy = false;
|
|
179052
|
-
}
|
|
179053
|
-
};
|
|
179054
|
-
refresh();
|
|
179055
|
-
const timer = setInterval(() => {
|
|
179056
|
-
refresh();
|
|
179057
|
-
}, 6e4);
|
|
179058
|
-
const onVisible = () => {
|
|
179059
|
-
refresh();
|
|
179060
|
-
};
|
|
179061
|
-
if (typeof document !== "undefined") document.addEventListener("visibilitychange", onVisible);
|
|
179062
|
-
return () => {
|
|
179063
|
-
controller.abort();
|
|
179064
|
-
clearInterval(timer);
|
|
179065
|
-
clearTimeout(retryTimer);
|
|
179066
|
-
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", onVisible);
|
|
179067
|
-
};
|
|
178953
|
+
if (active && accountKey !== void 0) return directory.watch(accountKey);
|
|
179068
178954
|
}, [
|
|
179069
178955
|
accountKey,
|
|
179070
178956
|
active,
|
|
179071
178957
|
directory
|
|
179072
178958
|
]);
|
|
178959
|
+
const summary = snapshot.summary;
|
|
178960
|
+
const count = summary?.state === "disabled" ? null : summary?.totalCount;
|
|
178961
|
+
const hint = summary?.state === "disabled" ? "目录暂不可用" : count == null ? summary?.state === "building" ? "整理中…" : snapshot.error || summary?.state === "failed" ? "暂时无法更新" : "" : (summary?.unseenCount ?? 0) > 0 ? tr$1("新识别 {v0} 个", { v0: summary.unseenCount }) : "";
|
|
179073
178962
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
179074
178963
|
"data-arkme-feedback": "recording-action",
|
|
179075
178964
|
type: "button",
|
|
@@ -179103,12 +178992,12 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
179103
178992
|
},
|
|
179104
178993
|
children: tr$1("已识别说话人")
|
|
179105
178994
|
}),
|
|
179106
|
-
|
|
178995
|
+
count != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
179107
178996
|
style: {
|
|
179108
178997
|
flexShrink: 0,
|
|
179109
178998
|
fontVariantNumeric: "tabular-nums"
|
|
179110
178999
|
},
|
|
179111
|
-
children:
|
|
179000
|
+
children: count
|
|
179112
179001
|
}),
|
|
179113
179002
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$21, {
|
|
179114
179003
|
size: 12,
|
|
@@ -179116,14 +179005,14 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
179116
179005
|
"aria-hidden": true
|
|
179117
179006
|
})
|
|
179118
179007
|
]
|
|
179119
|
-
}),
|
|
179008
|
+
}), hint && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
179120
179009
|
style: {
|
|
179121
179010
|
fontSize: 11,
|
|
179122
179011
|
lineHeight: "15px",
|
|
179123
179012
|
fontWeight: 400
|
|
179124
179013
|
},
|
|
179125
179014
|
"aria-live": "polite",
|
|
179126
|
-
children: tr$1(
|
|
179015
|
+
children: tr$1(hint)
|
|
179127
179016
|
})]
|
|
179128
179017
|
});
|
|
179129
179018
|
}
|
|
@@ -191460,6 +191349,28 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191460
191349
|
});
|
|
191461
191350
|
}
|
|
191462
191351
|
//#endregion
|
|
191352
|
+
//#region src/client/recognized-speaker-order.ts
|
|
191353
|
+
const preferenceKey = (accountKey) => `dsh-arkme:recognized-speaker-order:v1:${accountKey}`;
|
|
191354
|
+
function browserStorage() {
|
|
191355
|
+
try {
|
|
191356
|
+
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
191357
|
+
} catch {
|
|
191358
|
+
return;
|
|
191359
|
+
}
|
|
191360
|
+
}
|
|
191361
|
+
function readRecognizedSpeakerOrder(accountKey, storage = browserStorage()) {
|
|
191362
|
+
try {
|
|
191363
|
+
return storage?.getItem(preferenceKey(accountKey)) === "recent" ? "recent" : "frequent";
|
|
191364
|
+
} catch {
|
|
191365
|
+
return "frequent";
|
|
191366
|
+
}
|
|
191367
|
+
}
|
|
191368
|
+
function writeRecognizedSpeakerOrder(accountKey, order, storage = browserStorage()) {
|
|
191369
|
+
try {
|
|
191370
|
+
storage?.setItem(preferenceKey(accountKey), order);
|
|
191371
|
+
} catch {}
|
|
191372
|
+
}
|
|
191373
|
+
//#endregion
|
|
191463
191374
|
//#region src/client/recordings/SpeakerSelfGuide.tsx
|
|
191464
191375
|
const loadVoiceprint = (signal) => callArkme("voiceprint.status", {}, signal);
|
|
191465
191376
|
function SpeakerSelfGuide({ onOpenRecordings, readVoiceprint = loadVoiceprint }) {
|
|
@@ -191482,7 +191393,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191482
191393
|
if (state.loading) return null;
|
|
191483
191394
|
const pending = state.value?.enrollmentPending === true;
|
|
191484
191395
|
const hasVoiceprint = state.value?.hasVoiceprint === true;
|
|
191485
|
-
const title = pending ? "你的声纹正在处理中" : hasVoiceprint ? "已录入声纹,暂未在录音中匹配到你" : "还没有标记你的声音";
|
|
191396
|
+
const title = state.value === void 0 ? "声纹状态暂不可用" : pending ? "你的声纹正在处理中" : hasVoiceprint ? "已录入声纹,暂未在录音中匹配到你" : "还没有标记你的声音";
|
|
191486
191397
|
const actionStyle = {
|
|
191487
191398
|
border: 0,
|
|
191488
191399
|
padding: 0,
|
|
@@ -191537,39 +191448,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191537
191448
|
}
|
|
191538
191449
|
//#endregion
|
|
191539
191450
|
//#region src/client/ArkmeRecognizedSpeakersSurface.tsx
|
|
191540
|
-
/** Group only by a stable owner identity, never by a shared name or speaker number. */
|
|
191541
|
-
function identifiedSpeakerRows(options, candidates) {
|
|
191542
|
-
const marked = /* @__PURE__ */ new Map();
|
|
191543
|
-
for (const option of options) {
|
|
191544
|
-
if (option.kind !== "speaker") continue;
|
|
191545
|
-
const key = option.personKey || option.optionKey;
|
|
191546
|
-
if (marked.has(key)) continue;
|
|
191547
|
-
marked.set(key, {
|
|
191548
|
-
kind: "marked",
|
|
191549
|
-
key,
|
|
191550
|
-
optionKey: option.optionKey,
|
|
191551
|
-
speakerRef: option.speakerRef,
|
|
191552
|
-
name: option.label.trim() || "未命名说话人",
|
|
191553
|
-
...option.avatarRef === void 0 ? {} : { avatarRef: option.avatarRef },
|
|
191554
|
-
isCurrentUser: option.isCurrentUser
|
|
191555
|
-
});
|
|
191556
|
-
}
|
|
191557
|
-
const unmarked = /* @__PURE__ */ new Map();
|
|
191558
|
-
for (const candidate of candidates) {
|
|
191559
|
-
if (unmarked.has(candidate.candidateRef)) continue;
|
|
191560
|
-
unmarked.set(candidate.candidateRef, {
|
|
191561
|
-
kind: "unmarked",
|
|
191562
|
-
key: candidate.candidateRef,
|
|
191563
|
-
name: tr$1("说话人 {v0}", { v0: candidate.speakerToken?.trim() || candidate.displayName }),
|
|
191564
|
-
token: candidate.speakerToken?.trim() || "",
|
|
191565
|
-
subtitle: candidate.subtitle,
|
|
191566
|
-
candidateRef: candidate.candidateRef,
|
|
191567
|
-
dayCount: candidate.appearanceDays,
|
|
191568
|
-
lastSeenAt: candidate.latestAtMillis
|
|
191569
|
-
});
|
|
191570
|
-
}
|
|
191571
|
-
return [...[...marked.values()].sort((left, right) => left.name.localeCompare(right.name)), ...unmarked.values()];
|
|
191572
|
-
}
|
|
191573
191451
|
const styles$20 = {
|
|
191574
191452
|
root: {
|
|
191575
191453
|
flex: 1,
|
|
@@ -191757,87 +191635,133 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191757
191635
|
borderBottom: `1px solid ${arkmeTheme.borderSoft}`
|
|
191758
191636
|
}
|
|
191759
191637
|
};
|
|
191760
|
-
const defaultLoadMarkedMembers =
|
|
191638
|
+
const defaultLoadMarkedMembers = (speakerRef, signal, expectedVersion) => callArkme("recordings.speaker.members", {
|
|
191761
191639
|
speakerRef,
|
|
191762
191640
|
...expectedVersion === void 0 ? {} : { expectedVersion }
|
|
191763
191641
|
}, signal);
|
|
191764
|
-
|
|
191765
|
-
|
|
191766
|
-
|
|
191767
|
-
|
|
191768
|
-
if (
|
|
191769
|
-
|
|
191770
|
-
|
|
191771
|
-
|
|
191772
|
-
|
|
191773
|
-
|
|
191774
|
-
|
|
191775
|
-
|
|
191776
|
-
|
|
191777
|
-
|
|
191778
|
-
|
|
191779
|
-
})
|
|
191780
|
-
|
|
191781
|
-
|
|
191782
|
-
|
|
191783
|
-
|
|
191784
|
-
|
|
191785
|
-
|
|
191786
|
-
loading: true,
|
|
191787
|
-
error: ""
|
|
191642
|
+
const failureMessage = (error) => error instanceof Error ? error.message : tr$1("说话人列表暂时无法加载");
|
|
191643
|
+
const nameSegmenter = new Intl.Segmenter("zh-CN", { granularity: "grapheme" });
|
|
191644
|
+
function speakerNameAvatarFallback(row) {
|
|
191645
|
+
const initial = nameSegmenter.segment(row.displayName.trim())[Symbol.iterator]().next().value?.segment;
|
|
191646
|
+
if (!initial) return void 0;
|
|
191647
|
+
let hash = 0;
|
|
191648
|
+
for (const character of row.personKey) hash = Math.imul(hash, 31) + character.codePointAt(0) >>> 0;
|
|
191649
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
191650
|
+
"aria-hidden": true,
|
|
191651
|
+
style: {
|
|
191652
|
+
width: "100%",
|
|
191653
|
+
height: "100%",
|
|
191654
|
+
display: "grid",
|
|
191655
|
+
placeItems: "center",
|
|
191656
|
+
borderRadius: "50%",
|
|
191657
|
+
background: `color-mix(in srgb, ${recordingSpeakerColor(hash % 15)} 30%, ${arkmeTheme.base})`,
|
|
191658
|
+
color: arkmeTheme.text,
|
|
191659
|
+
fontSize: 17,
|
|
191660
|
+
fontWeight: 600,
|
|
191661
|
+
lineHeight: 1
|
|
191662
|
+
},
|
|
191663
|
+
children: initial
|
|
191788
191664
|
});
|
|
191665
|
+
}
|
|
191666
|
+
function personStats(row) {
|
|
191667
|
+
const recent = row.lastSeenAt > 0 ? new Intl.DateTimeFormat(arkmeIntlLocale(), {
|
|
191668
|
+
year: "numeric",
|
|
191669
|
+
month: "2-digit",
|
|
191670
|
+
day: "2-digit",
|
|
191671
|
+
hour: "2-digit",
|
|
191672
|
+
minute: "2-digit",
|
|
191673
|
+
hour12: false
|
|
191674
|
+
}).format(row.lastSeenAt) : tr$1("时间未知");
|
|
191675
|
+
return tr$1("出现 {v0} 天 · 最近 {v1}", {
|
|
191676
|
+
v0: row.dayCount,
|
|
191677
|
+
v1: recent
|
|
191678
|
+
});
|
|
191679
|
+
}
|
|
191680
|
+
function statusText(status) {
|
|
191681
|
+
if (status?.state === "disabled") return tr$1("说话人目录暂不可用,请稍后再试。");
|
|
191682
|
+
if (status?.coverage === "unknown") return status.state === "failed" ? tr$1("说话人目录暂不可用,请稍后刷新。") : tr$1("正在整理说话人目录…");
|
|
191683
|
+
if (status?.state === "failed") return tr$1("更新暂未完成,当前显示上次整理的目录。");
|
|
191684
|
+
if (status?.state === "stale") return tr$1("正在更新,当前显示已整理的目录。");
|
|
191685
|
+
if (status && (status.processingSessionCount > 0 || status.pendingIdentityAggregationCount > 0 || status.insufficientEvidenceCount > 0 || status.scanTruncated)) return tr$1("部分录音仍在整理,人物可能继续更新。");
|
|
191686
|
+
return "";
|
|
191687
|
+
}
|
|
191688
|
+
function PersonDetail({ row, accountKey, directory, loadMembers, onChanged }) {
|
|
191689
|
+
const [detail, setDetail] = (0, react$1.useState)();
|
|
191690
|
+
const [members, setMembers] = (0, react$1.useState)();
|
|
191691
|
+
const [error, setError] = (0, react$1.useState)("");
|
|
191692
|
+
const [revision, setRevision] = (0, react$1.useState)(0);
|
|
191789
191693
|
(0, react$1.useEffect)(() => {
|
|
191790
191694
|
const controller = new AbortController();
|
|
191791
|
-
|
|
191792
|
-
|
|
191793
|
-
|
|
191794
|
-
|
|
191795
|
-
|
|
191796
|
-
|
|
191797
|
-
|
|
191798
|
-
|
|
191695
|
+
let retry;
|
|
191696
|
+
setDetail(void 0);
|
|
191697
|
+
setMembers(void 0);
|
|
191698
|
+
setError("");
|
|
191699
|
+
directory.open(accountKey, row.detailRef, controller.signal).then(async (value) => {
|
|
191700
|
+
if (controller.signal.aborted) return;
|
|
191701
|
+
setDetail(value);
|
|
191702
|
+
if (value.type === "speaker") {
|
|
191703
|
+
const result = await loadMembers(value.speakerRef, controller.signal, value.expectedVersion);
|
|
191799
191704
|
if (controller.signal.aborted) return;
|
|
191800
|
-
|
|
191801
|
-
|
|
191802
|
-
|
|
191803
|
-
|
|
191804
|
-
});
|
|
191805
|
-
if (result.state === "stale" && result.version !== void 0 && result.version !== version) onVersionChanged();
|
|
191806
|
-
if (result.state !== "fresh") timer = setTimeout(() => {
|
|
191807
|
-
load();
|
|
191705
|
+
setMembers(result);
|
|
191706
|
+
if (result.state === "stale") onChanged();
|
|
191707
|
+
else if (result.state !== "fresh") retry = setTimeout(() => {
|
|
191708
|
+
if (directoryVisible()) setRevision((value) => value + 1);
|
|
191808
191709
|
}, Math.max(5e3, result.retryAfterMs ?? 1e4));
|
|
191809
|
-
} catch (error) {
|
|
191810
|
-
if (!controller.signal.aborted) setState({
|
|
191811
|
-
loading: false,
|
|
191812
|
-
error: failureMessage(error)
|
|
191813
|
-
});
|
|
191814
191710
|
}
|
|
191815
|
-
}
|
|
191816
|
-
|
|
191711
|
+
}).catch((error) => {
|
|
191712
|
+
if (controller.signal.aborted) return;
|
|
191713
|
+
if (directoryErrorCode(error) === "unmarked-candidate-not-found") onChanged();
|
|
191714
|
+
else setError(failureMessage(error));
|
|
191715
|
+
});
|
|
191817
191716
|
return () => {
|
|
191818
|
-
clearTimeout(timer);
|
|
191819
191717
|
controller.abort();
|
|
191718
|
+
clearTimeout(retry);
|
|
191820
191719
|
};
|
|
191821
191720
|
}, [
|
|
191721
|
+
row.detailRef,
|
|
191822
191722
|
accountKey,
|
|
191823
|
-
|
|
191723
|
+
directory,
|
|
191824
191724
|
loadMembers,
|
|
191825
|
-
|
|
191826
|
-
|
|
191725
|
+
onChanged,
|
|
191726
|
+
revision
|
|
191827
191727
|
]);
|
|
191728
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
191729
|
+
role: "alert",
|
|
191730
|
+
style: styles$20.error,
|
|
191731
|
+
children: [
|
|
191732
|
+
error,
|
|
191733
|
+
" ",
|
|
191734
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
191735
|
+
style: styles$20.button,
|
|
191736
|
+
onClick: () => setRevision((value) => value + 1),
|
|
191737
|
+
children: tr$1("重试")
|
|
191738
|
+
})
|
|
191739
|
+
]
|
|
191740
|
+
});
|
|
191741
|
+
if (!detail) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191742
|
+
role: "status",
|
|
191743
|
+
style: styles$20.state,
|
|
191744
|
+
children: tr$1("正在加载人物详情…")
|
|
191745
|
+
});
|
|
191746
|
+
if (detail.type === "candidate") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerDetail, {
|
|
191747
|
+
accountKey,
|
|
191748
|
+
candidateRef: detail.candidateRef,
|
|
191749
|
+
onDirectoryRefresh: onChanged,
|
|
191750
|
+
onCandidateCleared: onChanged
|
|
191751
|
+
});
|
|
191828
191752
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
191829
191753
|
"aria-label": tr$1("已标记说话人详情"),
|
|
191830
191754
|
children: [
|
|
191831
191755
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
|
|
191832
191756
|
style: styles$20.detailTitle,
|
|
191833
|
-
children: [
|
|
191757
|
+
children: [row.displayName, row.isSelf ? ` · ${tr$1("我")}` : ""]
|
|
191834
191758
|
}),
|
|
191835
191759
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
191836
191760
|
style: {
|
|
191837
191761
|
...styles$20.meta,
|
|
191838
191762
|
margin: 0
|
|
191839
191763
|
},
|
|
191840
|
-
children:
|
|
191764
|
+
children: personStats(row)
|
|
191841
191765
|
}),
|
|
191842
191766
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
191843
191767
|
style: styles$20.detailSection,
|
|
@@ -191846,30 +191770,20 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191846
191770
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
191847
191771
|
style: {
|
|
191848
191772
|
...styles$20.meta,
|
|
191849
|
-
margin: "0 0 8px",
|
|
191850
191773
|
whiteSpace: "normal"
|
|
191851
191774
|
},
|
|
191852
191775
|
children: tr$1("展示全部历史已转写片段中可核实的关联。")
|
|
191853
191776
|
}),
|
|
191854
|
-
|
|
191777
|
+
!members || members.state !== "fresh" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191855
191778
|
role: "status",
|
|
191856
191779
|
style: styles$20.state,
|
|
191857
|
-
children: tr$1("
|
|
191858
|
-
}) :
|
|
191859
|
-
role: "alert",
|
|
191860
|
-
style: styles$20.error,
|
|
191861
|
-
children: state.error || tr$1("出现统计暂不可用")
|
|
191862
|
-
}) : state.result?.state === "stale" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191863
|
-
role: "status",
|
|
191864
|
-
style: styles$20.state,
|
|
191865
|
-
children: tr$1("出现统计更新中")
|
|
191866
|
-
}) : state.result?.items.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191867
|
-
role: "status",
|
|
191780
|
+
children: members?.state === "failed" ? tr$1("出现统计暂不可用") : tr$1("出现统计整理中")
|
|
191781
|
+
}) : members.items.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191868
191782
|
style: styles$20.state,
|
|
191869
|
-
children:
|
|
191783
|
+
children: tr$1("暂无可核实的关联说话人。")
|
|
191870
191784
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
191871
191785
|
style: styles$20.list,
|
|
191872
|
-
children:
|
|
191786
|
+
children: members.items.map((member) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
191873
191787
|
style: styles$20.memberRow,
|
|
191874
191788
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerTokenAvatar, {
|
|
191875
191789
|
token: member.token,
|
|
@@ -191890,274 +191804,251 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191890
191804
|
]
|
|
191891
191805
|
});
|
|
191892
191806
|
}
|
|
191893
|
-
function ArkmeRecognizedSpeakersSurface(
|
|
191807
|
+
function ArkmeRecognizedSpeakersSurface(props) {
|
|
191808
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DirectorySurface, { ...props }, props.accountKey);
|
|
191809
|
+
}
|
|
191810
|
+
function DirectorySurface({ accountKey, onBack, directory = recognizedSpeakerDirectory, loadMarkedMembers = defaultLoadMarkedMembers }) {
|
|
191894
191811
|
useArkmeLocale();
|
|
191895
|
-
const directory = (0, react$1.useMemo)(() => providedDirectory ?? (loadMarked === readSpeakerOptions && loadUnmarked === readSpeakerPage && loadPresence === readSpeakerPresence ? recognizedSpeakerDirectory : new RecognizedSpeakerDirectory({
|
|
191896
|
-
marked: loadMarked,
|
|
191897
|
-
page: loadUnmarked,
|
|
191898
|
-
presence: loadPresence
|
|
191899
|
-
}, 0)), [
|
|
191900
|
-
providedDirectory,
|
|
191901
|
-
loadMarked,
|
|
191902
|
-
loadUnmarked,
|
|
191903
|
-
loadPresence
|
|
191904
|
-
]);
|
|
191905
191812
|
const [filter, setFilter] = (0, react$1.useState)("all");
|
|
191906
|
-
const [
|
|
191907
|
-
const [
|
|
191908
|
-
|
|
191909
|
-
|
|
191910
|
-
|
|
191911
|
-
|
|
191912
|
-
|
|
191913
|
-
|
|
191914
|
-
|
|
191915
|
-
|
|
191916
|
-
|
|
191917
|
-
|
|
191918
|
-
|
|
191919
|
-
|
|
191920
|
-
|
|
191921
|
-
|
|
191922
|
-
|
|
191923
|
-
const [
|
|
191924
|
-
|
|
191925
|
-
|
|
191926
|
-
|
|
191927
|
-
|
|
191928
|
-
|
|
191929
|
-
|
|
191930
|
-
|
|
191931
|
-
|
|
191932
|
-
|
|
191933
|
-
|
|
191934
|
-
|
|
191935
|
-
|
|
191936
|
-
|
|
191937
|
-
|
|
191938
|
-
|
|
191813
|
+
const [input, setInput] = (0, react$1.useState)(""), [queryText, setQueryText] = (0, react$1.useState)("");
|
|
191814
|
+
const [sort, setSort] = (0, react$1.useState)(() => readRecognizedSpeakerOrder(accountKey));
|
|
191815
|
+
const query = (0, react$1.useMemo)(() => ({
|
|
191816
|
+
filter,
|
|
191817
|
+
sort,
|
|
191818
|
+
query: queryText
|
|
191819
|
+
}), [
|
|
191820
|
+
filter,
|
|
191821
|
+
sort,
|
|
191822
|
+
queryText
|
|
191823
|
+
]);
|
|
191824
|
+
const [list, setList] = (0, react$1.useState)();
|
|
191825
|
+
const listRef = (0, react$1.useRef)(list);
|
|
191826
|
+
listRef.current = list;
|
|
191827
|
+
const [loading, setLoading] = (0, react$1.useState)(true), [moreLoading, setMoreLoading] = (0, react$1.useState)(false);
|
|
191828
|
+
const [error, setError] = (0, react$1.useState)(""), [seenError, setSeenError] = (0, react$1.useState)("");
|
|
191829
|
+
const [selected, setSelected] = (0, react$1.useState)();
|
|
191830
|
+
const [avatars, setAvatars] = (0, react$1.useState)({});
|
|
191831
|
+
const rootRef = (0, react$1.useRef)(null), listScroll = (0, react$1.useRef)(0), hadSelection = (0, react$1.useRef)(false);
|
|
191832
|
+
(0, react$1.useLayoutEffect)(() => {
|
|
191833
|
+
const root = rootRef.current;
|
|
191834
|
+
if (root && root.clientWidth <= 680) {
|
|
191835
|
+
if (selected && !hadSelection.current) {
|
|
191836
|
+
listScroll.current = root.scrollTop;
|
|
191837
|
+
root.scrollTop = 0;
|
|
191838
|
+
} else if (!selected && hadSelection.current) root.scrollTop = listScroll.current;
|
|
191839
|
+
}
|
|
191840
|
+
hadSelection.current = selected !== void 0;
|
|
191841
|
+
}, [selected]);
|
|
191842
|
+
const [revision, setRevision] = (0, react$1.useState)(0);
|
|
191843
|
+
const force = (0, react$1.useRef)(false), recoveryAttempts = (0, react$1.useRef)(0);
|
|
191844
|
+
const controllerRef = (0, react$1.useRef)();
|
|
191845
|
+
const snapshot = (0, react$1.useSyncExternalStore)(directory.subscribe, () => directory.get(accountKey), () => directory.get(accountKey));
|
|
191846
|
+
const summary = snapshot.summary;
|
|
191847
|
+
const queryValid = directoryQueryValid(input);
|
|
191848
|
+
const queryPending = normalizeDirectoryQuery(input) !== queryText;
|
|
191849
|
+
const listMatches = list?.query.filter === filter && list.query.sort === sort && list.query.query === queryText;
|
|
191939
191850
|
(0, react$1.useEffect)(() => {
|
|
191940
|
-
|
|
191851
|
+
if (!directory.hasPendingSeen(accountKey)) setSeenError("");
|
|
191941
191852
|
}, [
|
|
191853
|
+
directory,
|
|
191942
191854
|
accountKey,
|
|
191943
|
-
|
|
191944
|
-
query,
|
|
191945
|
-
order
|
|
191855
|
+
snapshot
|
|
191946
191856
|
]);
|
|
191857
|
+
(0, react$1.useEffect)(() => {
|
|
191858
|
+
const timer = setTimeout(() => setQueryText(normalizeDirectoryQuery(input)), 300);
|
|
191859
|
+
return () => clearTimeout(timer);
|
|
191860
|
+
}, [input]);
|
|
191861
|
+
const refresh = (0, react$1.useCallback)(() => {
|
|
191862
|
+
force.current = true;
|
|
191863
|
+
directory.invalidate(accountKey);
|
|
191864
|
+
setRevision((value) => value + 1);
|
|
191865
|
+
}, [directory, accountKey]);
|
|
191947
191866
|
(0, react$1.useEffect)(() => {
|
|
191948
191867
|
const controller = new AbortController();
|
|
191949
|
-
|
|
191950
|
-
|
|
191951
|
-
|
|
191952
|
-
|
|
191953
|
-
|
|
191954
|
-
|
|
191955
|
-
|
|
191956
|
-
|
|
191957
|
-
|
|
191958
|
-
|
|
191959
|
-
|
|
191960
|
-
|
|
191961
|
-
|
|
191962
|
-
|
|
191963
|
-
|
|
191964
|
-
|
|
191965
|
-
|
|
191966
|
-
|
|
191967
|
-
});
|
|
191968
|
-
setUnmarked({
|
|
191969
|
-
loading: true,
|
|
191970
|
-
complete: false,
|
|
191971
|
-
items: [],
|
|
191972
|
-
projectionState: void 0,
|
|
191973
|
-
error: ""
|
|
191974
|
-
});
|
|
191975
|
-
setOrderPreference({
|
|
191976
|
-
accountKey,
|
|
191977
|
-
value: readRecognizedSpeakerOrder(accountKey)
|
|
191978
|
-
});
|
|
191979
|
-
setQuery("");
|
|
191980
|
-
setSelectedMarked(void 0);
|
|
191981
|
-
setSelectedCandidate(void 0);
|
|
191982
|
-
}
|
|
191983
|
-
setMarked((previous) => ({
|
|
191984
|
-
...previous,
|
|
191985
|
-
loading: true,
|
|
191986
|
-
error: ""
|
|
191987
|
-
}));
|
|
191988
|
-
setPresence((previous) => ({
|
|
191989
|
-
...previous,
|
|
191990
|
-
loading: true,
|
|
191991
|
-
error: ""
|
|
191992
|
-
}));
|
|
191993
|
-
setUnmarked((previous) => ({
|
|
191994
|
-
...previous,
|
|
191995
|
-
loading: true,
|
|
191996
|
-
complete: false,
|
|
191997
|
-
error: ""
|
|
191998
|
-
}));
|
|
191999
|
-
const cachedMarked = directory.peekMarked(accountKey);
|
|
192000
|
-
if (cachedMarked !== void 0) setMarked({
|
|
192001
|
-
loading: false,
|
|
192002
|
-
items: cachedMarked,
|
|
192003
|
-
error: ""
|
|
192004
|
-
});
|
|
192005
|
-
const readMarked = () => {
|
|
192006
|
-
directory.readMarked(accountKey, controller.signal).then((items) => {
|
|
192007
|
-
if (!controller.signal.aborted) setMarked({
|
|
192008
|
-
loading: false,
|
|
192009
|
-
items,
|
|
192010
|
-
error: ""
|
|
192011
|
-
});
|
|
192012
|
-
}).catch((error) => {
|
|
191868
|
+
controllerRef.current = controller;
|
|
191869
|
+
let retry;
|
|
191870
|
+
let busy = false;
|
|
191871
|
+
const cached = directory.peek(accountKey, query);
|
|
191872
|
+
setList(cached);
|
|
191873
|
+
setSelected(void 0);
|
|
191874
|
+
setError("");
|
|
191875
|
+
setMoreLoading(false);
|
|
191876
|
+
const load = async () => {
|
|
191877
|
+
if (busy || !directoryVisible() || controller.signal.aborted) return;
|
|
191878
|
+
if (!directoryQueryValid(query.query)) {
|
|
191879
|
+
setLoading(false);
|
|
191880
|
+
return;
|
|
191881
|
+
}
|
|
191882
|
+
busy = true;
|
|
191883
|
+
setLoading(true);
|
|
191884
|
+
try {
|
|
191885
|
+
const result = await directory.first(accountKey, query, controller.signal, force.current);
|
|
192013
191886
|
if (!controller.signal.aborted) {
|
|
192014
|
-
|
|
192015
|
-
|
|
192016
|
-
|
|
192017
|
-
error: failureMessage(error)
|
|
192018
|
-
}));
|
|
192019
|
-
retry(error, readMarked);
|
|
191887
|
+
force.current = false;
|
|
191888
|
+
setList(result);
|
|
191889
|
+
setError("");
|
|
192020
191890
|
}
|
|
192021
|
-
})
|
|
191891
|
+
} catch (error) {
|
|
191892
|
+
if (controller.signal.aborted) return;
|
|
191893
|
+
setError(failureMessage(error));
|
|
191894
|
+
const delay = speakerRetryDelay(error);
|
|
191895
|
+
if (delay !== void 0) retry = setTimeout(() => {
|
|
191896
|
+
load();
|
|
191897
|
+
}, delay);
|
|
191898
|
+
} finally {
|
|
191899
|
+
busy = false;
|
|
191900
|
+
if (!controller.signal.aborted) setLoading(false);
|
|
191901
|
+
}
|
|
192022
191902
|
};
|
|
192023
|
-
|
|
192024
|
-
const
|
|
192025
|
-
|
|
192026
|
-
|
|
192027
|
-
|
|
192028
|
-
error: ""
|
|
191903
|
+
load();
|
|
191904
|
+
const unwatch = directory.watch(accountKey, () => {
|
|
191905
|
+
if (controller.signal.aborted) return;
|
|
191906
|
+
const current = listRef.current;
|
|
191907
|
+
if (!current || current.coverage === "unknown" || directory.needsReload(accountKey, current)) load();
|
|
192029
191908
|
});
|
|
192030
|
-
|
|
192031
|
-
|
|
192032
|
-
|
|
192033
|
-
|
|
192034
|
-
result,
|
|
192035
|
-
error: ""
|
|
192036
|
-
});
|
|
192037
|
-
}).catch((error) => {
|
|
192038
|
-
if (!controller.signal.aborted) {
|
|
192039
|
-
setPresence((previous) => ({
|
|
192040
|
-
...previous,
|
|
192041
|
-
loading: false,
|
|
192042
|
-
error: failureMessage(error)
|
|
192043
|
-
}));
|
|
192044
|
-
retry(error, readPresence);
|
|
192045
|
-
}
|
|
192046
|
-
});
|
|
191909
|
+
return () => {
|
|
191910
|
+
controller.abort();
|
|
191911
|
+
clearTimeout(retry);
|
|
191912
|
+
unwatch();
|
|
192047
191913
|
};
|
|
192048
|
-
|
|
192049
|
-
|
|
192050
|
-
|
|
192051
|
-
|
|
192052
|
-
|
|
192053
|
-
|
|
192054
|
-
|
|
192055
|
-
|
|
192056
|
-
|
|
192057
|
-
|
|
192058
|
-
|
|
192059
|
-
|
|
192060
|
-
|
|
192061
|
-
|
|
192062
|
-
loading: false,
|
|
192063
|
-
error: ""
|
|
192064
|
-
});
|
|
192065
|
-
}).catch((error) => {
|
|
192066
|
-
if (!controller.signal.aborted) {
|
|
192067
|
-
setUnmarked((previous) => ({
|
|
192068
|
-
...previous,
|
|
192069
|
-
loading: false,
|
|
192070
|
-
complete: false,
|
|
192071
|
-
error: failureMessage(error)
|
|
192072
|
-
}));
|
|
192073
|
-
retry(error, readCandidates);
|
|
191914
|
+
}, [
|
|
191915
|
+
accountKey,
|
|
191916
|
+
directory,
|
|
191917
|
+
query,
|
|
191918
|
+
revision
|
|
191919
|
+
]);
|
|
191920
|
+
(0, react$1.useEffect)(() => {
|
|
191921
|
+
if (!list || loading || queryPending || list.query.filter !== filter || list.query.query !== queryText) return;
|
|
191922
|
+
let disposed = false;
|
|
191923
|
+
const confirm = () => {
|
|
191924
|
+
if (directoryVisible()) directory.confirmDisplayed(accountKey, list).then(() => {
|
|
191925
|
+
if (!disposed) {
|
|
191926
|
+
setSeenError("");
|
|
191927
|
+
if (directory.needsReload(accountKey, list)) refresh();
|
|
192074
191928
|
}
|
|
191929
|
+
}).catch(() => {
|
|
191930
|
+
if (!disposed) setSeenError(tr$1("查看状态暂未同步,联网后自动重试。"));
|
|
192075
191931
|
});
|
|
192076
191932
|
};
|
|
192077
|
-
|
|
191933
|
+
confirm();
|
|
191934
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", confirm);
|
|
192078
191935
|
return () => {
|
|
192079
|
-
|
|
192080
|
-
|
|
191936
|
+
disposed = true;
|
|
191937
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", confirm);
|
|
192081
191938
|
};
|
|
192082
191939
|
}, [
|
|
192083
191940
|
accountKey,
|
|
192084
|
-
|
|
192085
|
-
|
|
191941
|
+
directory,
|
|
191942
|
+
list,
|
|
191943
|
+
loading,
|
|
191944
|
+
queryPending,
|
|
191945
|
+
filter,
|
|
191946
|
+
queryText,
|
|
191947
|
+
refresh
|
|
192086
191948
|
]);
|
|
191949
|
+
const recoverDetail = (0, react$1.useCallback)(() => {
|
|
191950
|
+
if (!selected || recoveryAttempts.current >= 1) {
|
|
191951
|
+
setSelected(void 0);
|
|
191952
|
+
refresh();
|
|
191953
|
+
return;
|
|
191954
|
+
}
|
|
191955
|
+
recoveryAttempts.current += 1;
|
|
191956
|
+
const controller = controllerRef.current;
|
|
191957
|
+
if (!controller) return;
|
|
191958
|
+
directory.first(accountKey, query, controller.signal, true).then((next) => {
|
|
191959
|
+
if (controller.signal.aborted) return;
|
|
191960
|
+
setList(next);
|
|
191961
|
+
setSelected(next.items.find((item) => item.personKey === selected.personKey));
|
|
191962
|
+
}).catch((error) => {
|
|
191963
|
+
if (!controller.signal.aborted) {
|
|
191964
|
+
setSelected(void 0);
|
|
191965
|
+
setError(failureMessage(error));
|
|
191966
|
+
}
|
|
191967
|
+
});
|
|
191968
|
+
}, [
|
|
191969
|
+
accountKey,
|
|
191970
|
+
directory,
|
|
191971
|
+
selected,
|
|
191972
|
+
query,
|
|
191973
|
+
refresh
|
|
191974
|
+
]);
|
|
191975
|
+
const loadMore = async () => {
|
|
191976
|
+
const controller = controllerRef.current;
|
|
191977
|
+
if (!list || !controller || moreLoading || queryPending) return;
|
|
191978
|
+
setMoreLoading(true);
|
|
191979
|
+
setError("");
|
|
191980
|
+
try {
|
|
191981
|
+
const next = await directory.more(accountKey, list, controller.signal);
|
|
191982
|
+
if (!controller.signal.aborted) setList(next);
|
|
191983
|
+
} catch (error) {
|
|
191984
|
+
if (!controller.signal.aborted) setError(failureMessage(error));
|
|
191985
|
+
} finally {
|
|
191986
|
+
if (!controller.signal.aborted) setMoreLoading(false);
|
|
191987
|
+
}
|
|
191988
|
+
};
|
|
191989
|
+
const disabled = summary?.state === "disabled" || list?.state === "disabled";
|
|
191990
|
+
const rows = disabled || queryPending || !listMatches ? [] : list?.items ?? [];
|
|
191991
|
+
const avatarBatch = JSON.stringify(rows.filter((row) => row.type === "marked" && avatars[row.detailRef] === void 0).slice(0, 50).map((row) => row.detailRef));
|
|
192087
191992
|
(0, react$1.useEffect)(() => {
|
|
192088
|
-
const
|
|
192089
|
-
if (
|
|
191993
|
+
const refs = JSON.parse(avatarBatch);
|
|
191994
|
+
if (refs.length === 0) return;
|
|
192090
191995
|
const controller = new AbortController();
|
|
192091
|
-
|
|
192092
|
-
|
|
192093
|
-
|
|
192094
|
-
|
|
192095
|
-
|
|
192096
|
-
|
|
192097
|
-
|
|
192098
|
-
|
|
192099
|
-
|
|
191996
|
+
let retry;
|
|
191997
|
+
let busy = false, retryAt = 0;
|
|
191998
|
+
const load = async () => {
|
|
191999
|
+
if (!directoryVisible() || controller.signal.aborted || busy) return;
|
|
192000
|
+
if (retryAt > Date.now()) {
|
|
192001
|
+
clearTimeout(retry);
|
|
192002
|
+
retry = setTimeout(() => {
|
|
192003
|
+
load();
|
|
192004
|
+
}, retryAt - Date.now());
|
|
192005
|
+
return;
|
|
192006
|
+
}
|
|
192007
|
+
busy = true;
|
|
192008
|
+
try {
|
|
192009
|
+
const result = await directory.avatars(accountKey, refs, controller.signal);
|
|
192010
|
+
if (controller.signal.aborted) return;
|
|
192011
|
+
const resolved = new Map(result.map((item) => [item.detailRef, item.avatarRef]));
|
|
192012
|
+
setAvatars((previous) => ({
|
|
192100
192013
|
...previous,
|
|
192101
|
-
|
|
192102
|
-
error: failureMessage(error)
|
|
192014
|
+
...Object.fromEntries(refs.map((ref) => [ref, resolved.get(ref) || null]))
|
|
192103
192015
|
}));
|
|
192104
|
-
})
|
|
192105
|
-
|
|
192016
|
+
} catch (error) {
|
|
192017
|
+
if (controller.signal.aborted) return;
|
|
192018
|
+
const delay = speakerRetryDelay(error);
|
|
192019
|
+
if (delay !== void 0) {
|
|
192020
|
+
retryAt = Date.now() + Math.max(15e3, delay);
|
|
192021
|
+
retry = setTimeout(() => {
|
|
192022
|
+
load();
|
|
192023
|
+
}, retryAt - Date.now());
|
|
192024
|
+
}
|
|
192025
|
+
} finally {
|
|
192026
|
+
busy = false;
|
|
192027
|
+
}
|
|
192028
|
+
};
|
|
192029
|
+
const wake = () => {
|
|
192030
|
+
clearTimeout(retry);
|
|
192031
|
+
load();
|
|
192032
|
+
};
|
|
192033
|
+
load();
|
|
192034
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", wake);
|
|
192035
|
+
if (typeof window !== "undefined") window.addEventListener("online", wake);
|
|
192106
192036
|
return () => {
|
|
192107
|
-
clearTimeout(timer);
|
|
192108
192037
|
controller.abort();
|
|
192038
|
+
clearTimeout(retry);
|
|
192039
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", wake);
|
|
192040
|
+
if (typeof window !== "undefined") window.removeEventListener("online", wake);
|
|
192109
192041
|
};
|
|
192110
192042
|
}, [
|
|
192111
192043
|
accountKey,
|
|
192112
|
-
refreshRevision,
|
|
192113
192044
|
directory,
|
|
192114
|
-
|
|
192115
|
-
presence.error,
|
|
192116
|
-
presence.result
|
|
192117
|
-
]);
|
|
192118
|
-
const refreshPresenceVersion = (0, react$1.useCallback)(() => {
|
|
192119
|
-
setPresence({
|
|
192120
|
-
loading: false,
|
|
192121
|
-
result: {
|
|
192122
|
-
state: "stale",
|
|
192123
|
-
scope: "all-history",
|
|
192124
|
-
items: [],
|
|
192125
|
-
retryAfterMs: 1e3
|
|
192126
|
-
},
|
|
192127
|
-
error: ""
|
|
192128
|
-
});
|
|
192129
|
-
}, []);
|
|
192130
|
-
const rows = (0, react$1.useMemo)(() => identifiedSpeakerRows(marked.items, unmarked.items), [marked.items, unmarked.items]);
|
|
192131
|
-
const hasSelf = rows.some((row) => row.kind === "marked" && row.isCurrentUser);
|
|
192132
|
-
(0, react$1.useEffect)(() => {
|
|
192133
|
-
if (readAccount.current !== accountKey || marked.loading || marked.error !== "") return;
|
|
192134
|
-
if (rows.length > 0 || !unmarked.loading && unmarked.complete) recognizedSpeakerTracker.acknowledge(accountKey);
|
|
192135
|
-
if (!unmarked.loading && unmarked.complete && unmarked.error === "") recognizedSpeakerTracker.observe(accountKey, marked.items, unmarked.items, true);
|
|
192136
|
-
}, [
|
|
192137
|
-
accountKey,
|
|
192138
|
-
marked.loading,
|
|
192139
|
-
marked.error,
|
|
192140
|
-
marked.items,
|
|
192141
|
-
unmarked.loading,
|
|
192142
|
-
unmarked.complete,
|
|
192143
|
-
unmarked.error,
|
|
192144
|
-
unmarked.items,
|
|
192145
|
-
rows.length
|
|
192045
|
+
avatarBatch
|
|
192146
192046
|
]);
|
|
192147
|
-
const
|
|
192148
|
-
const
|
|
192149
|
-
const
|
|
192150
|
-
const stat = row.kind === "marked" ? presenceByOption.get(row.optionKey) : unmarked.projectionState === void 0 || unmarked.projectionState === "fresh" ? row : void 0;
|
|
192151
|
-
return {
|
|
192152
|
-
key: `${row.kind}:${row.key}`,
|
|
192153
|
-
name: row.name,
|
|
192154
|
-
dayCount: stat?.dayCount,
|
|
192155
|
-
lastSeenAt: stat?.lastSeenAt
|
|
192156
|
-
};
|
|
192157
|
-
};
|
|
192158
|
-
const visible = rows.filter((row) => (filter === "all" || row.kind === filter) && (normalizedQuery === "" || row.name.toLocaleLowerCase().includes(normalizedQuery) || row.kind === "unmarked" && row.subtitle.toLocaleLowerCase().includes(normalizedQuery))).sort((left, right) => Number(right.kind === "marked" && right.isCurrentUser) - Number(left.kind === "marked" && left.isCurrentUser) || compareRecognizedSpeakers(orderValue(left), orderValue(right), order));
|
|
192159
|
-
const loading = marked.loading || unmarked.loading;
|
|
192047
|
+
const state = disabled ? tr$1("说话人目录暂不可用,请稍后再试。") : statusText(summary?.snapshotVersion === list?.snapshotVersion ? summary : list?.coverage === "complete" ? list : summary);
|
|
192048
|
+
const hasNewVersion = list?.coverage === "complete" && summary?.snapshotVersion && summary.snapshotVersion !== list.snapshotVersion;
|
|
192049
|
+
const selfMissing = listMatches && filter === "all" && queryText === "" && !queryPending && list?.coverage === "complete" && list.state === "fresh" && !list.items.some((row) => row.isSelf);
|
|
192160
192050
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192051
|
+
ref: rootRef,
|
|
192161
192052
|
style: styles$20.root,
|
|
192162
192053
|
"data-arkme-owned": "recognized-speakers-surface",
|
|
192163
192054
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
|
|
@@ -192197,6 +192088,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
192197
192088
|
marginLeft: "auto"
|
|
192198
192089
|
},
|
|
192199
192090
|
onClick: refresh,
|
|
192091
|
+
disabled: loading,
|
|
192200
192092
|
children: tr$1("刷新")
|
|
192201
192093
|
})
|
|
192202
192094
|
]
|
|
@@ -192205,41 +192097,44 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
192205
192097
|
style: styles$20.filters,
|
|
192206
192098
|
children: [
|
|
192207
192099
|
[
|
|
192208
|
-
[
|
|
192209
|
-
|
|
192210
|
-
|
|
192211
|
-
|
|
192100
|
+
[
|
|
192101
|
+
"all",
|
|
192102
|
+
"全部",
|
|
192103
|
+
summary?.totalCount
|
|
192104
|
+
],
|
|
192105
|
+
[
|
|
192106
|
+
"marked",
|
|
192107
|
+
"已标记",
|
|
192108
|
+
summary?.markedCount
|
|
192109
|
+
],
|
|
192110
|
+
[
|
|
192111
|
+
"unmarked",
|
|
192112
|
+
"未标记",
|
|
192113
|
+
summary?.unmarkedCount
|
|
192114
|
+
]
|
|
192115
|
+
].map(([kind, label, count]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192212
192116
|
type: "button",
|
|
192213
192117
|
"aria-pressed": filter === kind,
|
|
192214
192118
|
style: {
|
|
192215
192119
|
...styles$20.filter,
|
|
192216
192120
|
...filter === kind ? styles$20.selectedFilter : {}
|
|
192217
192121
|
},
|
|
192218
|
-
onClick: () =>
|
|
192219
|
-
|
|
192220
|
-
setSelectedCandidate(void 0);
|
|
192221
|
-
setSelectedMarked(void 0);
|
|
192222
|
-
},
|
|
192223
|
-
children: tr$1(label)
|
|
192122
|
+
onClick: () => setFilter(kind),
|
|
192123
|
+
children: [tr$1(label), !disabled && count != null ? ` ${count}` : ""]
|
|
192224
192124
|
}, kind)),
|
|
192225
192125
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
192226
192126
|
"aria-label": tr$1("搜索说话人"),
|
|
192227
|
-
placeholder: tr$1("
|
|
192228
|
-
value:
|
|
192229
|
-
onChange: (event) =>
|
|
192230
|
-
setQuery(event.target.value);
|
|
192231
|
-
},
|
|
192127
|
+
placeholder: tr$1("搜索名称或编号"),
|
|
192128
|
+
value: input,
|
|
192129
|
+
onChange: (event) => setInput(event.target.value),
|
|
192232
192130
|
style: styles$20.search
|
|
192233
192131
|
}),
|
|
192234
192132
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
192235
192133
|
"aria-label": tr$1("说话人排序"),
|
|
192236
|
-
value:
|
|
192134
|
+
value: sort,
|
|
192237
192135
|
onChange: (event) => {
|
|
192238
192136
|
const next = event.target.value === "recent" ? "recent" : "frequent";
|
|
192239
|
-
|
|
192240
|
-
accountKey,
|
|
192241
|
-
value: next
|
|
192242
|
-
});
|
|
192137
|
+
setSort(next);
|
|
192243
192138
|
writeRecognizedSpeakerOrder(accountKey, next);
|
|
192244
192139
|
},
|
|
192245
192140
|
style: styles$20.sort,
|
|
@@ -192253,186 +192148,115 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
192253
192148
|
})
|
|
192254
192149
|
]
|
|
192255
192150
|
}),
|
|
192256
|
-
!
|
|
192151
|
+
!queryValid && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192152
|
+
role: "alert",
|
|
192153
|
+
style: styles$20.error,
|
|
192154
|
+
children: tr$1("搜索内容过长,请缩短至 256 字节以内。")
|
|
192155
|
+
}),
|
|
192156
|
+
selfMissing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SpeakerSelfGuide, { onOpenRecordings: onBack }, accountKey),
|
|
192157
|
+
hasNewVersion && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192158
|
+
role: "status",
|
|
192159
|
+
style: styles$20.note,
|
|
192160
|
+
children: tr$1("目录有更新,刷新后查看最新人物。")
|
|
192161
|
+
}),
|
|
192162
|
+
state && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192163
|
+
role: "status",
|
|
192164
|
+
style: styles$20.note,
|
|
192165
|
+
children: state
|
|
192166
|
+
}),
|
|
192167
|
+
seenError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192168
|
+
role: "status",
|
|
192169
|
+
style: styles$20.note,
|
|
192170
|
+
children: seenError
|
|
192171
|
+
}),
|
|
192172
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192173
|
+
role: "alert",
|
|
192174
|
+
style: styles$20.error,
|
|
192175
|
+
children: error
|
|
192176
|
+
}),
|
|
192257
192177
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192258
192178
|
className: "arkme-recognized-speakers-grid",
|
|
192259
|
-
"data-detail-open":
|
|
192260
|
-
children: [
|
|
192261
|
-
|
|
192262
|
-
|
|
192263
|
-
|
|
192264
|
-
|
|
192265
|
-
|
|
192266
|
-
|
|
192267
|
-
|
|
192268
|
-
|
|
192269
|
-
|
|
192270
|
-
|
|
192271
|
-
|
|
192272
|
-
|
|
192273
|
-
|
|
192274
|
-
marked.error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192275
|
-
role: "alert",
|
|
192276
|
-
style: styles$20.error,
|
|
192277
|
-
children: [
|
|
192278
|
-
tr$1("已标记说话人读取失败:"),
|
|
192279
|
-
" ",
|
|
192280
|
-
marked.error
|
|
192281
|
-
]
|
|
192282
|
-
}),
|
|
192283
|
-
unmarked.error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192284
|
-
role: "alert",
|
|
192285
|
-
style: styles$20.error,
|
|
192286
|
-
children: [
|
|
192287
|
-
tr$1("未标记说话人读取失败:"),
|
|
192288
|
-
" ",
|
|
192289
|
-
unmarked.error
|
|
192290
|
-
]
|
|
192291
|
-
}),
|
|
192292
|
-
unmarked.projectionState === "building" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192293
|
-
role: "status",
|
|
192294
|
-
style: styles$20.state,
|
|
192295
|
-
children: tr$1("未标记说话人正在整理,结果可能不完整。")
|
|
192296
|
-
}),
|
|
192297
|
-
unmarked.projectionState === "stale" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192298
|
-
role: "status",
|
|
192299
|
-
style: styles$20.state,
|
|
192300
|
-
children: tr$1("未标记说话人正在更新,结果可能不完整。")
|
|
192301
|
-
}),
|
|
192302
|
-
unmarked.projectionState === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192303
|
-
role: "alert",
|
|
192304
|
-
style: styles$20.error,
|
|
192305
|
-
children: tr$1("未标记说话人整理失败,请稍后刷新。")
|
|
192306
|
-
}),
|
|
192307
|
-
loading && rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192308
|
-
role: "status",
|
|
192309
|
-
style: styles$20.state,
|
|
192310
|
-
children: tr$1("正在加载说话人…")
|
|
192311
|
-
}) : visible.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192312
|
-
role: "status",
|
|
192313
|
-
style: styles$20.state,
|
|
192314
|
-
children: loading ? tr$1("正在更新说话人…") : rows.length === 0 && marked.error === "" && unmarked.error === "" && (unmarked.projectionState === void 0 || unmarked.projectionState === "fresh") ? tr$1("暂无已识别说话人") : tr$1("暂无可显示的说话人")
|
|
192315
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
192316
|
-
style: styles$20.list,
|
|
192317
|
-
children: visible.slice(0, visibleCount).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: row.kind === "unmarked" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192318
|
-
type: "button",
|
|
192319
|
-
className: "arkme-recognized-speakers-row",
|
|
192320
|
-
"aria-current": selectedCandidate === row.candidateRef ? "true" : void 0,
|
|
192321
|
-
style: {
|
|
192322
|
-
...styles$20.row,
|
|
192323
|
-
cursor: "pointer"
|
|
192324
|
-
},
|
|
192325
|
-
onClick: () => {
|
|
192326
|
-
setSelectedCandidate(row.candidateRef);
|
|
192327
|
-
setSelectedMarked(void 0);
|
|
192328
|
-
},
|
|
192329
|
-
children: [
|
|
192330
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerTokenAvatar, {
|
|
192331
|
-
token: row.token,
|
|
192332
|
-
size: 38,
|
|
192333
|
-
label: row.name
|
|
192334
|
-
}),
|
|
192335
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192336
|
-
style: styles$20.copy,
|
|
192337
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192338
|
-
style: styles$20.name,
|
|
192339
|
-
children: row.name
|
|
192340
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192341
|
-
style: styles$20.meta,
|
|
192342
|
-
children: row.subtitle
|
|
192343
|
-
})]
|
|
192344
|
-
}),
|
|
192345
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192346
|
-
style: styles$20.badge,
|
|
192347
|
-
children: [tr$1("未标记"), " ›"]
|
|
192348
|
-
})
|
|
192349
|
-
]
|
|
192350
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192351
|
-
type: "button",
|
|
192352
|
-
className: "arkme-recognized-speakers-row",
|
|
192353
|
-
"aria-current": selectedMarked?.key === row.key ? "true" : void 0,
|
|
192354
|
-
style: {
|
|
192355
|
-
...styles$20.row,
|
|
192356
|
-
cursor: "pointer"
|
|
192357
|
-
},
|
|
192358
|
-
onClick: () => {
|
|
192359
|
-
setSelectedMarked(row);
|
|
192360
|
-
setSelectedCandidate(void 0);
|
|
192361
|
-
},
|
|
192362
|
-
children: [
|
|
192363
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeUserAvatar, {
|
|
192364
|
-
...row.avatarRef === void 0 ? {} : { avatarRef: row.avatarRef },
|
|
192365
|
-
size: 38,
|
|
192366
|
-
label: row.name
|
|
192367
|
-
}),
|
|
192368
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192369
|
-
style: styles$20.copy,
|
|
192370
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192371
|
-
style: styles$20.name,
|
|
192372
|
-
children: [row.name, row.isCurrentUser ? ` · ${tr$1("我")}` : ""]
|
|
192373
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192374
|
-
style: styles$20.meta,
|
|
192375
|
-
children: markedPresenceLabel(presenceByOption.get(row.optionKey), presence.result, presence.loading, presence.error)
|
|
192376
|
-
})]
|
|
192377
|
-
}),
|
|
192378
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192379
|
-
style: styles$20.badge,
|
|
192380
|
-
children: [tr$1("已标记"), " ›"]
|
|
192381
|
-
})
|
|
192382
|
-
]
|
|
192383
|
-
}) }, `${row.kind}:${row.key}`))
|
|
192384
|
-
}),
|
|
192385
|
-
visible.length > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192386
|
-
type: "button",
|
|
192387
|
-
style: {
|
|
192388
|
-
...styles$20.button,
|
|
192389
|
-
marginTop: 14
|
|
192390
|
-
},
|
|
192391
|
-
onClick: () => {
|
|
192392
|
-
setVisibleCount((count) => count + 100);
|
|
192393
|
-
},
|
|
192394
|
-
children: tr$1("显示更多说话人")
|
|
192395
|
-
})
|
|
192396
|
-
]
|
|
192397
|
-
}),
|
|
192398
|
-
selectedCandidate !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192399
|
-
style: styles$20.detail,
|
|
192400
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192179
|
+
"data-detail-open": selected !== void 0 ? "true" : "false",
|
|
192180
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192181
|
+
className: "arkme-recognized-speakers-list",
|
|
192182
|
+
"aria-busy": loading || queryPending,
|
|
192183
|
+
children: [!disabled && (loading || queryPending) && rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192184
|
+
role: "status",
|
|
192185
|
+
style: styles$20.state,
|
|
192186
|
+
children: tr$1("正在加载说话人…")
|
|
192187
|
+
}) : !disabled && !error && rows.length === 0 && list?.coverage === "complete" && !queryPending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192188
|
+
role: "status",
|
|
192189
|
+
style: styles$20.state,
|
|
192190
|
+
children: tr$1(queryText ? "没有匹配的说话人" : filter === "all" ? "暂无已识别说话人" : "该分类暂无说话人")
|
|
192191
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
192192
|
+
style: styles$20.list,
|
|
192193
|
+
children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192401
192194
|
type: "button",
|
|
192402
|
-
className: "arkme-recognized-speakers-
|
|
192403
|
-
|
|
192404
|
-
|
|
192405
|
-
|
|
192195
|
+
className: "arkme-recognized-speakers-row",
|
|
192196
|
+
"aria-current": selected?.personKey === row.personKey ? "true" : void 0,
|
|
192197
|
+
style: {
|
|
192198
|
+
...styles$20.row,
|
|
192199
|
+
cursor: "pointer"
|
|
192406
192200
|
},
|
|
192407
|
-
children: tr$1("‹ 返回列表")
|
|
192408
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerDetail, {
|
|
192409
|
-
accountKey,
|
|
192410
|
-
candidateRef: selectedCandidate,
|
|
192411
|
-
onDirectoryRefresh: refresh,
|
|
192412
|
-
onCandidateCleared: () => {
|
|
192413
|
-
setSelectedCandidate(void 0);
|
|
192414
|
-
}
|
|
192415
|
-
}, `${accountKey}:${selectedCandidate}`)]
|
|
192416
|
-
}),
|
|
192417
|
-
selectedMarked !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192418
|
-
style: styles$20.detail,
|
|
192419
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192420
|
-
type: "button",
|
|
192421
|
-
className: "arkme-recognized-speakers-mobile-back",
|
|
192422
|
-
style: styles$20.button,
|
|
192423
192201
|
onClick: () => {
|
|
192424
|
-
|
|
192202
|
+
recoveryAttempts.current = 0;
|
|
192203
|
+
setSelected(row);
|
|
192425
192204
|
},
|
|
192426
|
-
children:
|
|
192427
|
-
|
|
192428
|
-
|
|
192429
|
-
|
|
192430
|
-
|
|
192431
|
-
|
|
192432
|
-
|
|
192433
|
-
|
|
192434
|
-
|
|
192435
|
-
|
|
192205
|
+
children: [
|
|
192206
|
+
row.type === "unmarked" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerTokenAvatar, {
|
|
192207
|
+
token: row.displayNumber > 0 ? String(row.displayNumber) : "",
|
|
192208
|
+
size: 38,
|
|
192209
|
+
label: row.displayName
|
|
192210
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeUserAvatar, {
|
|
192211
|
+
...avatars[row.detailRef] ? { avatarRef: avatars[row.detailRef] } : {},
|
|
192212
|
+
fallbackContent: speakerNameAvatarFallback(row),
|
|
192213
|
+
size: 38,
|
|
192214
|
+
label: row.displayName
|
|
192215
|
+
}),
|
|
192216
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192217
|
+
style: styles$20.copy,
|
|
192218
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192219
|
+
style: styles$20.name,
|
|
192220
|
+
children: [row.displayName, row.isSelf ? ` · ${tr$1("我")}` : ""]
|
|
192221
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192222
|
+
style: styles$20.meta,
|
|
192223
|
+
children: personStats(row)
|
|
192224
|
+
})]
|
|
192225
|
+
}),
|
|
192226
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192227
|
+
style: styles$20.badge,
|
|
192228
|
+
children: [tr$1(row.type === "marked" ? "已标记" : "未标记"), " ›"]
|
|
192229
|
+
})
|
|
192230
|
+
]
|
|
192231
|
+
}) }, row.personKey))
|
|
192232
|
+
}), !disabled && !queryPending && list?.hasMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192233
|
+
type: "button",
|
|
192234
|
+
disabled: moreLoading || loading,
|
|
192235
|
+
style: {
|
|
192236
|
+
...styles$20.button,
|
|
192237
|
+
marginTop: 14
|
|
192238
|
+
},
|
|
192239
|
+
onClick: () => {
|
|
192240
|
+
loadMore();
|
|
192241
|
+
},
|
|
192242
|
+
children: tr$1(moreLoading ? "正在加载…" : "加载更多说话人")
|
|
192243
|
+
})]
|
|
192244
|
+
}), selected && !disabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192245
|
+
style: styles$20.detail,
|
|
192246
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192247
|
+
type: "button",
|
|
192248
|
+
className: "arkme-recognized-speakers-mobile-back",
|
|
192249
|
+
style: styles$20.button,
|
|
192250
|
+
onClick: () => setSelected(void 0),
|
|
192251
|
+
children: tr$1("‹ 返回列表")
|
|
192252
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonDetail, {
|
|
192253
|
+
row: selected,
|
|
192254
|
+
accountKey,
|
|
192255
|
+
directory,
|
|
192256
|
+
loadMembers: loadMarkedMembers,
|
|
192257
|
+
onChanged: recoverDetail
|
|
192258
|
+
}, selected.detailRef)]
|
|
192259
|
+
})]
|
|
192436
192260
|
})
|
|
192437
192261
|
]
|
|
192438
192262
|
})]
|
|
@@ -212840,7 +212664,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
212840
212664
|
const c$3 = e$20;
|
|
212841
212665
|
//#endregion
|
|
212842
212666
|
//#region package.json
|
|
212843
|
-
var version = "0.1.
|
|
212667
|
+
var version = "0.1.87";
|
|
212844
212668
|
//#endregion
|
|
212845
212669
|
//#region src/client/arkme-membership.ts
|
|
212846
212670
|
function membershipLabel(state) {
|