beIN Sports 1 variants stayed separated after projection because names with region prefixes (C Car, C Reu, Thai), time-shift suffixes (2h/4h/8h/12h) and language markers (En, Fr, Thai) produced distinct fingerprints. Extend normalization in the server projection service and the frontend grouping fallback to fold these into one logical channel, with tests on the exact reported names. Clarify the Laya language detection warning so a language-matching failure is not mistaken for a grouping failure, and bump script versions for cache refresh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
93 lines
4.5 KiB
JavaScript
93 lines
4.5 KiB
JavaScript
(function (root, factory) {
|
|
const service = factory();
|
|
if (typeof module === 'object' && module.exports) module.exports = service;
|
|
if (root) root.LayaStatusPresentation = service;
|
|
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
|
|
const PHASE_LABELS = {
|
|
idle: 'Model not downloaded',
|
|
checking: 'Checking local AI model…',
|
|
downloading: 'Downloading model…',
|
|
verifying: 'Verifying model…',
|
|
preparing: 'Preparing download…',
|
|
ready: 'Model ready',
|
|
failed: 'Model download failed',
|
|
deleting: 'Removing model…'
|
|
};
|
|
|
|
function errorParts(status) {
|
|
const value = status.error || status.lastError;
|
|
const fallback = status.lastError;
|
|
if (!value) return { message: '', detail: '' };
|
|
if (typeof value === 'string') return {
|
|
message: value,
|
|
detail: typeof fallback === 'object' ? String(fallback.detail || '') : ''
|
|
};
|
|
return {
|
|
message: String(value.message || 'The local AI model operation failed.'),
|
|
detail: String(value.detail || '')
|
|
};
|
|
}
|
|
|
|
function presentLayaStatus(status = {}, mode = 'algo') {
|
|
const phase = PHASE_LABELS[status.phase] ? status.phase : 'idle';
|
|
const busy = Boolean(status.downloading) || ['checking', 'downloading', 'verifying', 'preparing', 'deleting'].includes(phase);
|
|
const percentValue = Number(status.progressPercent);
|
|
const determined = phase === 'downloading' && status.progressPercent !== null &&
|
|
status.progressPercent !== undefined && Number.isFinite(percentValue);
|
|
const progressPercent = determined ? Math.max(0, Math.min(100, Math.round(percentValue))) : null;
|
|
const error = errorParts(status);
|
|
const failed = phase === 'failed';
|
|
const modelPresent = status.modelPresent === true;
|
|
const runtimeAvailable = status.runtimeAvailable === true;
|
|
const ready = modelPresent && runtimeAvailable && !busy && !failed;
|
|
const statusLabel = ready
|
|
? 'Ready'
|
|
: failed || busy
|
|
? PHASE_LABELS[phase]
|
|
: modelPresent && !runtimeAvailable
|
|
? 'Local AI service unavailable'
|
|
: !modelPresent
|
|
? 'Model not downloaded'
|
|
: PHASE_LABELS[phase];
|
|
return {
|
|
phase,
|
|
ready,
|
|
statusLabel,
|
|
modelLabel: `Model: ${modelPresent ? 'Downloaded' : 'Not downloaded'}`,
|
|
serviceLabel: `Local AI service: ${runtimeAvailable ? 'Available' : 'Unavailable'}`,
|
|
busy,
|
|
showProgress: phase === 'downloading',
|
|
progressIndeterminate: phase === 'downloading' && progressPercent === null,
|
|
progressPercent,
|
|
bytesDownloaded: status.bytesDownloaded !== null && status.bytesDownloaded !== undefined && Number.isFinite(Number(status.bytesDownloaded))
|
|
? Number(status.bytesDownloaded) : null,
|
|
totalBytes: status.totalBytes !== null && status.totalBytes !== undefined && Number.isFinite(Number(status.totalBytes))
|
|
? Number(status.totalBytes) : null,
|
|
errorMessage: failed ? (error.message || 'The local AI model could not be downloaded.') : '',
|
|
errorDetail: failed ? error.detail : '',
|
|
downloadLabel: failed ? 'Retry download' : 'Download model',
|
|
showDownload: !busy && !modelPresent && (phase === 'idle' || failed),
|
|
showRemove: !busy && modelPresent,
|
|
showUseStandard: failed && mode !== 'algo',
|
|
showCheckAgain: !busy && modelPresent && !runtimeAvailable,
|
|
showStartCommand: !busy && modelPresent && !runtimeAvailable,
|
|
availabilityMessage: modelPresent && !runtimeAvailable
|
|
? 'The model is installed, but the Local AI service is not running. Standard channel matching is being used.'
|
|
: ''
|
|
};
|
|
}
|
|
|
|
function channelListWarning(mode, status = {}, batchFailed = false) {
|
|
if (mode === 'algo') return '';
|
|
if (batchFailed) {
|
|
return 'Local AI language detection failed. Channels were grouped with Standard matching and remain available.';
|
|
}
|
|
if (status.modelPresent !== true || status.runtimeAvailable !== true) {
|
|
return 'Local AI service is unavailable. Standard channel matching is being used.';
|
|
}
|
|
return '';
|
|
}
|
|
|
|
return { channelListWarning, presentLayaStatus };
|
|
});
|