allow ajust sentences

This commit is contained in:
2026-08-30 11:07:50 +08:00
parent 508a26ba02
commit 0d0b82e095
9 changed files with 270 additions and 3 deletions

View File

@@ -106,6 +106,10 @@ dialog::backdrop { background: rgb(20 25 28 / 55%); }
.sentence-scroll { max-height: calc(100vh - 120px); overflow: auto; }
.sentence-scroll textarea { width: min(600px, 45vw); min-width: 260px; min-height: 58px; resize: vertical; padding: 7px; border: 1px solid #b8c0c7; border-radius: 3px; }
.sentence-scroll select { min-width: 90px; }
.boundary-control { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; white-space: nowrap; }
.boundary-control button { min-height: 24px; padding: 2px 6px; font-size: 11px; line-height: 1; }
.boundary-time { display: inline-block; min-width: 56px; text-align: center; font-variant-numeric: tabular-nums; }
.boundary-status { min-width: 26px; color: #a12622; font-size: 11px; }
@media (max-width: 820px) {
.topbar { align-items: stretch; flex-direction: column; padding: 14px 16px; }

View File

@@ -91,6 +91,6 @@
</div>
</dialog>
<script src="/static/admin.js?v=manual-split-v1" defer></script>
<script src="/static/admin.js?v=boundary-adjust-v1" defer></script>
</body>
</html>

View File

@@ -239,9 +239,13 @@ function sentenceRow(video, sentence) {
}
});
saveContainer.append(save);
const timeContainer = document.createElement("td");
const startLabel = document.createElement("span");
startLabel.textContent = formatDuration(sentence.start_ms);
timeContainer.append(startLabel, " — ", boundaryControl(video, sentence));
row.append(
textCell(String(sentence.index + 1)),
textCell(`${formatDuration(sentence.start_ms)} - ${formatDuration(sentence.end_ms)}`),
timeContainer,
textContainer,
languageContainer,
saveContainer,
@@ -249,6 +253,50 @@ function sentenceRow(video, sentence) {
return row;
}
function boundaryControl(video, sentence) {
const container = document.createElement("div");
container.className = "boundary-control";
const label = document.createElement("span");
label.className = "boundary-time";
label.textContent = formatDuration(sentence.end_ms);
const status = document.createElement("span");
status.className = "boundary-status";
async function adjust(deltaMs, changedButton) {
const buttons = [minus, plus];
buttons.forEach((item) => { item.disabled = true; });
status.textContent = "";
try {
await api(
`/api/v1/admin/videos/${video.video_hash}/sentences/${sentence.index}/boundary`,
{
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ delta_ms: deltaMs }),
},
);
await openSentences(video);
} catch (error) {
elements.serviceState.textContent = `分割点调整失败: ${error.message}`;
status.textContent = "失败";
buttons.forEach((item) => { item.disabled = false; });
window.setTimeout(() => { status.textContent = ""; }, 1800);
}
if (changedButton) {
window.setTimeout(() => {
changedButton.textContent = deltaMs < 0 ? "0.1" : "+0.1";
}, 900);
}
}
const minus = button("0.1", (event) => adjust(event.shiftKey ? -10 : -100, minus));
const plus = button("+0.1", (event) => adjust(event.shiftKey ? 10 : 100, plus));
minus.title = "结束点提前 0.1 秒;按住 Shift 微调 0.01 秒";
plus.title = "结束点延后 0.1 秒;按住 Shift 微调 0.01 秒";
container.append(minus, label, plus, status);
return container;
}
async function reprocess(videoHash) {
try {
await api(`/api/v1/admin/videos/${videoHash}/process`, { method: "POST" });