Сократить служебные теги SHiNE и сохранить обратную совместимость

This commit is contained in:
AidarKC
2026-08-12 13:14:23 +04:00
parent 4d80ab639e
commit 8f32e82d14
15 changed files with 144 additions and 86 deletions
+21 -7
View File
@@ -11,6 +11,16 @@ function defaultParsed(rawText = '') {
};
}
function hasTechPrefix(text = '', offset = 0) {
return String(text || '').startsWith('<SHiNE:', offset) || String(text || '').startsWith('<S:', offset);
}
function getTechPrefixLength(text = '', offset = 0) {
if (String(text || '').startsWith('<SHiNE:', offset)) return 7;
if (String(text || '').startsWith('<S:', offset)) return 3;
return 0;
}
function parseReplyId(value = '') {
const parts = String(value || '').split('|');
if (parts.length !== 4) return null;
@@ -57,41 +67,45 @@ function buildCallDisplayText(callSummary) {
export function sanitizeUserDmTextForSend(rawText = '') {
const text = String(rawText || '');
return text.startsWith('<SHiNE:') ? `< SHiNE:${text.slice(7)}` : text;
if (text.startsWith('<SHiNE:')) return `< SHiNE:${text.slice(7)}`;
if (text.startsWith('<S:')) return `< S:${text.slice(3)}`;
return text;
}
export function buildDmCallTechBlock({ status = '', durationSec = 0, reason = '' } = {}) {
const cleanStatus = String(status || '').trim().toLowerCase();
if (cleanStatus === 'completed') {
return `<SHiNE:call;v=1;status=completed;duration=${Math.max(0, Math.floor(Number(durationSec || 0)))}>`;
return `<S:call;v=1;status=completed;duration=${Math.max(0, Math.floor(Number(durationSec || 0)))}>`;
}
const cleanReason = String(reason || '').trim().toLowerCase();
return `<SHiNE:call;v=1;status=failed;reason=${cleanReason || 'connect_failed'}>`;
return `<S:call;v=1;status=failed;reason=${cleanReason || 'connect_failed'}>`;
}
export function buildDmReplyTechBlock({ baseKey = '' } = {}) {
const cleanBaseKey = String(baseKey || '').trim();
if (!cleanBaseKey) return '';
return `<SHiNE:reply;v=1;id=${cleanBaseKey}>`;
return `<S:reply;v=1;id=${cleanBaseKey}>`;
}
export function parseDmTechBlocks(rawText = '') {
const text = String(rawText || '');
if (!text.startsWith('<SHiNE:')) return defaultParsed(text);
if (!hasTechPrefix(text)) return defaultParsed(text);
const blocks = [];
let cursor = 0;
let replyRef = null;
let callSummary = null;
while (text.startsWith('<SHiNE:', cursor)) {
while (hasTechPrefix(text, cursor)) {
const end = text.indexOf('>', cursor);
if (end < 0) {
if (!blocks.length) return defaultParsed(text);
break;
}
const inner = text.slice(cursor + 7, end);
const prefixLength = getTechPrefixLength(text, cursor);
if (!prefixLength) break;
const inner = text.slice(cursor + prefixLength, end);
const segments = inner.split(';').map((part) => String(part || '').trim()).filter(Boolean);
if (!segments.length) {
if (!blocks.length) return defaultParsed(text);