151 lines
5.5 KiB
JavaScript
151 lines
5.5 KiB
JavaScript
(function (root, factory) {
|
|
"use strict";
|
|
|
|
const api = Object.freeze(factory());
|
|
if (typeof module === "object" && module.exports) module.exports = api;
|
|
if (root) root.MbnPlayoutSafety = api;
|
|
})(typeof globalThis === "object" ? globalThis : this, function () {
|
|
"use strict";
|
|
|
|
const connectionStates = new Set([
|
|
"disabled", "dry-run-ready", "disconnected", "connecting", "connected",
|
|
"reconnecting", "disconnecting", "faulted", "outcome-unknown", "disposed"
|
|
]);
|
|
|
|
function normalizeConnectionState(value) {
|
|
const normalized = String(value || "unavailable")
|
|
.trim()
|
|
.toLocaleLowerCase("en-US")
|
|
.replace(/[\s_]+/g, "-");
|
|
return connectionStates.has(normalized) ? normalized : "unavailable";
|
|
}
|
|
|
|
function responseTimeoutFromNative(value) {
|
|
const operationTimeout = Number(value);
|
|
if (!Number.isFinite(operationTimeout) || operationTimeout < 100 || operationTimeout > 300000) {
|
|
return 15000;
|
|
}
|
|
return Math.min(305000, Math.max(5100, Math.trunc(operationTimeout) + 5000));
|
|
}
|
|
|
|
function commandBlockReason(snapshot, command) {
|
|
if (!snapshot || snapshot.pending) return "busy";
|
|
if (snapshot.outcomeUnknown) return "outcome-unknown";
|
|
if (!snapshot.commandAvailable) return "unavailable";
|
|
if (snapshot.refreshFaulted && command !== "take-out") return "refresh-fault";
|
|
|
|
const onAir = snapshot.engineState === "PROGRAM" || Boolean(snapshot.onAirCode);
|
|
const prepared = snapshot.engineState === "PREPARED" || Boolean(snapshot.preparedCode);
|
|
if (command === "next" && !onAir) return "next-requires-on-air";
|
|
if (command === "take-in" && !prepared) return "take-in-requires-prepare";
|
|
if (command === "take-out" && !onAir && !prepared) return "nothing-to-take-out";
|
|
return null;
|
|
}
|
|
|
|
function legacyTakeInShortcutAction(snapshot) {
|
|
if (!snapshot || snapshot.pending) return "blocked";
|
|
if (!snapshot.takeInAllowed) return "take-in-locked";
|
|
if (snapshot.engineState === "PROGRAM" || snapshot.onAirCode) return "next-required";
|
|
if (snapshot.engineState === "PREPARED" || snapshot.preparedCode) return "take-in";
|
|
return "prepare-then-take-in";
|
|
}
|
|
|
|
function matchesPendingCommand(pending, payload) {
|
|
return Boolean(
|
|
pending && payload &&
|
|
payload.requestId === pending.requestId &&
|
|
payload.command === pending.command);
|
|
}
|
|
|
|
function canClearCommandError(error, sessionQuarantined) {
|
|
if (sessionQuarantined || !error) return !sessionQuarantined;
|
|
return error.outcomeUnknown !== true && error.code !== "WEB_TIMEOUT" &&
|
|
error.nonClearable !== true;
|
|
}
|
|
|
|
function playlistSnapshotLocked(snapshot) {
|
|
return Boolean(snapshot && (
|
|
snapshot.pending ||
|
|
snapshot.outcomeUnknown ||
|
|
snapshot.engineState === "PREPARED" ||
|
|
snapshot.engineState === "PROGRAM" ||
|
|
snapshot.preparedCode ||
|
|
snapshot.onAirCode));
|
|
}
|
|
|
|
function shouldClearRefreshError(error, refreshFaulted) {
|
|
return !refreshFaulted && error?.isRefreshFault === true;
|
|
}
|
|
|
|
function normalizeRefreshBudget(payload) {
|
|
const completed = Number.isSafeInteger(payload?.refreshCompletedCount) &&
|
|
payload.refreshCompletedCount >= 0 &&
|
|
payload.refreshCompletedCount <= 2147483647
|
|
? payload.refreshCompletedCount
|
|
: 0;
|
|
const maximum = Number.isSafeInteger(payload?.refreshMaximumCount) &&
|
|
payload.refreshMaximumCount >= 0 &&
|
|
payload.refreshMaximumCount <= 1000000
|
|
? payload.refreshMaximumCount
|
|
: null;
|
|
return {
|
|
completed,
|
|
maximum,
|
|
limitReached: maximum !== null && completed >= maximum &&
|
|
payload?.refreshLimitReached === true &&
|
|
payload?.refreshActive !== true &&
|
|
payload?.playCompletionPending !== true &&
|
|
payload?.refreshFaulted !== true
|
|
};
|
|
}
|
|
|
|
function formatRefreshBudgetState(payload, nextLabel = "WAIT") {
|
|
const budget = normalizeRefreshBudget(payload);
|
|
const count = budget.maximum === null
|
|
? String(budget.completed)
|
|
: `${budget.completed}/${budget.maximum}`;
|
|
if (payload?.refreshFaulted === true) return "FAULT";
|
|
if (budget.limitReached) return `CAPPED · ${count}`;
|
|
if (payload?.refreshActive === true) return `ACTIVE · ${count} · ${nextLabel}`;
|
|
return budget.maximum === null && budget.completed === 0
|
|
? "STOPPED"
|
|
: `STOPPED · ${count}`;
|
|
}
|
|
|
|
function isNewerDatabaseStatusSequence(latestSequence, incomingSequence) {
|
|
const latest = Number.isSafeInteger(latestSequence) && latestSequence >= 0
|
|
? latestSequence
|
|
: 0;
|
|
return Number.isSafeInteger(incomingSequence) &&
|
|
incomingSequence > 0 && incomingSequence > latest;
|
|
}
|
|
|
|
function resolveStoredCatalogIndex(catalog, builderKey, cutCode) {
|
|
if (!Array.isArray(catalog)) return -1;
|
|
const exact = catalog.findIndex(item =>
|
|
item && item.reachable !== false && item.builderKey === builderKey);
|
|
if (exact >= 0) return exact;
|
|
const code = String(cutCode || "");
|
|
return catalog.findIndex(item => {
|
|
if (!item || item.reachable === false) return false;
|
|
const aliases = Array.isArray(item.aliases) ? item.aliases : [String(item.code || "")];
|
|
return aliases.includes(code);
|
|
});
|
|
}
|
|
|
|
return {
|
|
normalizeConnectionState,
|
|
responseTimeoutFromNative,
|
|
commandBlockReason,
|
|
legacyTakeInShortcutAction,
|
|
matchesPendingCommand,
|
|
canClearCommandError,
|
|
playlistSnapshotLocked,
|
|
shouldClearRefreshError,
|
|
normalizeRefreshBudget,
|
|
formatRefreshBudgetState,
|
|
isNewerDatabaseStatusSequence,
|
|
resolveStoredCatalogIndex
|
|
};
|
|
});
|