Копирование в Word, длительность в списке, хранение две недели
Длительность в списке всегда была нулевой: при загрузке файл ещё не декодирован, и mark_done её не записывал. Кнопка копирования кладёт в буфер и разметку, и простой текст: Word берёт первое и сохраняет полужирные имена говорящих, простые редакторы - второе. Срок хранения поднят с 3 суток до 336 часов, после чистки выполняется VACUUM: SQLite помечает страницы свободными, но файл не уменьшает. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2382c7a700
commit
7dd49a11ec
+45
-1
@@ -174,11 +174,15 @@ def render_job(job: dict) -> str:
|
||||
.roles .line {{ display:grid; grid-template-columns:76px 1fr; gap:10px;
|
||||
padding:4px 0; border-bottom:1px solid var(--line); }}
|
||||
.who2 {{ font-weight:600; font-size:13px; }}
|
||||
button.copy {{ font:13px inherit; color:var(--fg); background:transparent;
|
||||
border:1px solid var(--line); border-radius:4px; padding:3px 10px;
|
||||
margin-left:10px; cursor:pointer; font-weight:400; }}
|
||||
button.copy:hover {{ border-color:var(--dim); }}
|
||||
</style></head><body><div class="wrap">
|
||||
<h1>Расшифровка {html.escape(str(job.get("job_id", ""))[:8])} - {html.escape(str(job.get("filename", "")))}</h1>
|
||||
<div class="stats">{_stats_row(job)}</div>
|
||||
|
||||
<h2>Что отдал сервис</h2>
|
||||
<h2>Что отдал сервис <button class="copy" data-src="plain">скопировать для Word</button></h2>
|
||||
<div class="hint">Реплики так, как их нарезал сервис. Г0 значит, что разделение
|
||||
по голосам выключено и говорящий неизвестен - это норма.</div>
|
||||
{"".join(rows) or "<div class=hint>реплик нет</div>"}
|
||||
@@ -187,6 +191,7 @@ def render_job(job: dict) -> str:
|
||||
{roles_block}
|
||||
<div id="check" class="hint"></div>
|
||||
<div id="out" class="roles"></div>
|
||||
<button class="copy" id="copyroles" data-src="roles" hidden>скопировать диалог для Word</button>
|
||||
</div>
|
||||
<script>
|
||||
const S = {payload};
|
||||
@@ -212,6 +217,45 @@ function draw() {{
|
||||
if (r !== prev) {{ flush(); prev = r; start = s.start; }}
|
||||
buf.push(s.text.replace(/[&<>]/g, c => ({{'&':'&','<':'<','>':'>'}})[c])); }});
|
||||
flush(); out.innerHTML = html;
|
||||
const rolesButton = document.getElementById('copyroles');
|
||||
if (rolesButton) rolesButton.hidden = !html;
|
||||
}}
|
||||
if (box) box.addEventListener('input', draw);
|
||||
|
||||
// Word вставляет из буфера разметку, если она есть: имена говорящих
|
||||
// останутся полужирными, а абзацы - абзацами. Простой текст кладём рядом,
|
||||
// для редакторов, которые разметку не берут.
|
||||
function collect(src) {{
|
||||
if (src === 'roles') {{
|
||||
const lines = [...out.querySelectorAll('.line')].map(el => [
|
||||
el.querySelector('.who2').textContent.trim(),
|
||||
el.lastElementChild.textContent.trim()]);
|
||||
return lines;
|
||||
}}
|
||||
return [...document.querySelectorAll('.turn')].map(el => [
|
||||
el.querySelector('.tc').textContent.trim() + ' ' +
|
||||
el.querySelector('.who').textContent.trim(),
|
||||
el.querySelector('.text').textContent.trim()]);
|
||||
}}
|
||||
function esc(t) {{ return t.replace(/[&<>]/g, c => ({{'&':'&','<':'<','>':'>'}}[c])); }}
|
||||
async function copyAs(src, button) {{
|
||||
const rows = collect(src);
|
||||
if (!rows.length) return;
|
||||
const plain = rows.map(([who, text]) => who + ': ' + text).join('\\n\\n');
|
||||
const rich = '<div>' + rows.map(([who, text]) =>
|
||||
'<p><b>' + esc(who) + ':</b> ' + esc(text) + '</p>').join('') + '</div>';
|
||||
try {{
|
||||
await navigator.clipboard.write([new ClipboardItem({{
|
||||
'text/html': new Blob([rich], {{type: 'text/html'}}),
|
||||
'text/plain': new Blob([plain], {{type: 'text/plain'}})}})]);
|
||||
}} catch (e) {{
|
||||
// Старые браузеры и небезопасное соединение: кладём хотя бы текст.
|
||||
await navigator.clipboard.writeText(plain);
|
||||
}}
|
||||
const was = button.textContent;
|
||||
button.textContent = 'скопировано';
|
||||
setTimeout(() => {{ button.textContent = was; }}, 1500);
|
||||
}}
|
||||
document.querySelectorAll('button.copy').forEach(b =>
|
||||
b.addEventListener('click', () => copyAs(b.dataset.src, b)));
|
||||
</script></body></html>"""
|
||||
|
||||
Reference in New Issue
Block a user