diff --git a/H3-CONSOLE.md b/H3-CONSOLE.md index 8e13227..a9aeba9 100644 --- a/H3-CONSOLE.md +++ b/H3-CONSOLE.md @@ -136,6 +136,17 @@ Calling it on several jobs in a row puts the most-recently-prioritized one at position 1 and pushes the others back slightly — still clusters them all near the front, just not in a guaranteed relative order between themselves. +### `POST {base}/v1/videos/{id}/cancel` +Genuinely cancels a `queued`/`running` job — unlike `DELETE` (below), which +only hides it from listings but lets it keep consuming compute. Confirmed +live 2026-09-09: cancelling a queued job flips its `status` to `cancelled`, +sets `error` to `"用户手动取消"` and `finished_at`, and the cluster's +`queued` count in `GET /v1/backends` actually decrements. Use this (not +DELETE) to actually stop a duplicate/unwanted queued job. +```json +{ "id": "6361be157e48", "status": "cancelled", "error": "用户手动取消", ... } +``` + ### `GET {base}/v1/videos/{id}/file` Downloads the mp4. `Content-Type: video/mp4`, supports range requests (`Accept-Ranges: bytes`), `Content-Disposition: attachment`. Auth via diff --git a/admin-dance-library.html b/admin-dance-library.html index d5580d7..ad61afa 100644 --- a/admin-dance-library.html +++ b/admin-dance-library.html @@ -39,6 +39,12 @@ .pub-badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 12px; white-space: nowrap; } .pub-on { background: #eef7ee; color: #2e7d32; } .pub-off { background: #f0f0f0; color: var(--muted); } + /* 高清重绘: one cell per resolution tier — either a small preview (done), + a disabled "生成中…" state, or a "生成高清版" button (not generated yet). */ + td.hd-cell { min-width: 110px; } + td.hd-cell video { display: block; width: 100px; height: auto; max-height: 160px; object-fit: contain; background: #000; border-radius: 4px; margin-bottom: 4px; } + td.hd-cell .hd-status { font-size: 12px; color: var(--muted); } + td.hd-cell .hd-status.hd-failed { color: #c0392b; } @@ -87,6 +93,13 @@ + + ${hdCell(c, HD_RENDER_TIERS[0])} + ${hdCell(c, HD_RENDER_TIERS[1])} ${characterCell(c)} ${garmentCell(c)} ${danceRefCell(c)} @@ -333,6 +415,8 @@ function render() { ${escapeHtml((c.fullPrompt || "").slice(0, 80))}${(c.fullPrompt || "").length > 80 ? "…" : ""} ${videoHref(c)} + ${hdCell(c, HD_RENDER_TIERS[0])} + ${hdCell(c, HD_RENDER_TIERS[1])} ${characterCell(c)} ${garmentCell(c)} ${danceRefCell(c)} @@ -357,7 +441,7 @@ function render() { // Loading preload="metadata" for every row at once would hammer the // /lib/video proxy (each clip is a fresh H3 Console fetch); only pull a // row's first frame once it's actually scrolled into view. - tbody.querySelectorAll("td.preview video[data-src], td.ref-thumb video[data-src]").forEach((v) => previewObserver.observe(v)); + tbody.querySelectorAll("td.preview video[data-src], td.ref-thumb video[data-src], td.hd-cell video[data-src]").forEach((v) => previewObserver.observe(v)); tbody.querySelectorAll("[data-edit]").forEach((b) => b.addEventListener("click", () => { editingId = b.dataset.edit; render(); })); tbody.querySelectorAll("[data-cancel]").forEach((b) => b.addEventListener("click", () => { editingId = null; render(); })); @@ -396,6 +480,33 @@ function render() { else b.disabled = false; }) ); + tbody.querySelectorAll("[data-hd-gen]").forEach((b) => + b.addEventListener("click", async () => { + const id = b.dataset.hdGen; + const width = Number(b.dataset.width); + const height = Number(b.dataset.height); + b.disabled = true; + b.textContent = "提交中…"; + try { + const res = await fetch(`/api/admin/library/${id}/hd-render`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ width, height }), + }); + const data = await res.json().catch(() => ({})); + if (!res.ok) { + alert(data.error || "提交失败"); + b.disabled = false; + b.textContent = "生成高清版"; + return; + } + await loadLibrary(); // re-render shows "生成中…" (or the finished preview, if H3 happened to return cached:true) + } catch { + b.disabled = false; + b.textContent = "生成高清版"; + } + }) + ); tbody.querySelectorAll("[data-qc-check]").forEach((b) => b.addEventListener("click", async () => { const id = b.dataset.qcCheck; @@ -435,6 +546,7 @@ document.getElementById("garmentFilter").addEventListener("change", render); document.getElementById("danceRefFilter").addEventListener("change", render); document.getElementById("qcFilter").addEventListener("change", render); document.getElementById("publishFilter").addEventListener("change", render); +document.getElementById("hdFilter").addEventListener("change", render); document.getElementById("addBtn").addEventListener("click", async () => { const errorBox = document.getElementById("addError"); diff --git a/blacklist.json b/blacklist.json new file mode 100644 index 0000000..a3eca8c --- /dev/null +++ b/blacklist.json @@ -0,0 +1,10 @@ +[ + { + "id": "69a398b4-b36d-4756-85d5-6ba76f9efb9c", + "createdAt": 1789886140463, + "targetType": "character", + "targetId": "8b992ec5-c320-499d-b380-a5907c897474", + "reason": "跟 Moera 长得太像,用户反馈需要下架", + "createdBy": null + } +] \ No newline at end of file diff --git a/dance-refs.json b/dance-refs.json index 69b18cf..d5a9c91 100644 --- a/dance-refs.json +++ b/dance-refs.json @@ -104,7 +104,8 @@ "durationSec": null, "motionDescriptor": "双手举至脸颊两侧比划框脸手势,俏皮可爱,上身动作为主", "copyrightSource": "test_placeholder", - "isActive": true + "isActive": true, + "h3AssetUrl": "http://192.168.110.67:8080/assets/fba12b3d62e548ba__0638d68c-0aac-442e-b9ee-5a7f60f6cc65.mp4" }, { "id": "dee22838-4453-4386-9bed-4d69c78cd85f", @@ -547,7 +548,8 @@ "durationSec": null, "motionDescriptor": "单臂弯举靠近脸侧,头部微仰侧倾,慵懒俏皮的展示姿态", "copyrightSource": "test_placeholder", - "isActive": true + "isActive": true, + "h3AssetUrl": "http://192.168.110.67:8080/assets/3ec07a69bf86413f__96577e07-f4f9-49d8-9870-2591e561cf51.mp4" }, { "id": "40c054ee-3a52-4865-b965-8f695821be03", diff --git a/dance-rooms.html b/dance-rooms.html index 4aa311a..547e57a 100644 --- a/dance-rooms.html +++ b/dance-rooms.html @@ -9,11 +9,15 @@ \n\n\n

The page you requested was not found.

\n

Sorry, the page you are looking for is currently unavailable.
\nPlease try again later.

\n

The server is powered by frp.

\n

Faithfully yours, frp.

\n\n\n" + }, + { + "id": "9727af09-db7f-4c1d-bb89-f60a612634b2", + "createdAt": 1789943860908, + "kind": "hd_render", + "sourceClipId": "9331f7792dca", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "3da0ae2f-4baa-486b-9128-47379b8864f3", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "1140b062ef10", + "error": null, + "generatedVideoId": "1140b062ef10" + }, + { + "id": "a529227f-41a4-415d-ae54-ecd181734d04", + "createdAt": 1789946534133, + "kind": "hd_render", + "sourceClipId": "d34bcfb5eff6", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "34f2baac-5d14-4f5d-9e11-3baede1aaa65", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "be202ec5902b", + "error": null, + "generatedVideoId": "be202ec5902b" + }, + { + "id": "59d72383-6867-465d-9a6b-7a198a58e934", + "createdAt": 1789949207188, + "kind": "hd_render", + "sourceClipId": "dc0186259e10", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "97efeea4-6f90-4092-90dd-ba27540d5682", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "6246cff70f4a", + "error": null, + "generatedVideoId": "6246cff70f4a" + }, + { + "id": "12b2f664-120e-497f-8cdd-38e229f05712", + "createdAt": 1789951840102, + "kind": "hd_render", + "sourceClipId": "3600d90d0cfd", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "1645498f-ccc4-48c8-a195-15b7b18241db", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "04392c0995df", + "error": null, + "generatedVideoId": "04392c0995df" + }, + { + "id": "f3cbb576-19e4-4712-a41f-9483b934e79b", + "createdAt": 1789954472677, + "kind": "hd_render", + "sourceClipId": "5ac883f42315", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "c370a3fd-bef6-41b1-90c2-a0a56de8bb47", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "2e3f14163e1a", + "error": null, + "generatedVideoId": "2e3f14163e1a" + }, + { + "id": "f39dc334-a35f-4e71-82b5-d8228247a37e", + "createdAt": 1789957105542, + "kind": "hd_render", + "sourceClipId": "5542fa48c846", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "28ae0935-5a8c-45a3-89be-b39a53f91773", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "bd8b8c814b98", + "error": null, + "generatedVideoId": "bd8b8c814b98" + }, + { + "id": "c908e226-173b-4f69-addd-08eef2f21883", + "createdAt": 1789959778524, + "kind": "hd_render", + "sourceClipId": "415763622860", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "da733477-b2b9-4a7c-b042-a347e8e4b412", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "c42a4b7b0720", + "error": null, + "generatedVideoId": "c42a4b7b0720" + }, + { + "id": "f239ce27-bd8f-419f-93e6-cb6f453d7a40", + "createdAt": 1789962491554, + "kind": "hd_render", + "sourceClipId": "7765c19d1afe", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "6215327f-7c51-46ba-b344-75a9f575cb9e", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "43c330b1bc11", + "error": null, + "generatedVideoId": "43c330b1bc11" + }, + { + "id": "8b8f978a-f962-4f33-bdcc-2c9efb63d5a9", + "createdAt": 1789965506200, + "kind": "hd_render", + "sourceClipId": "d86bfe9114ee", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "3490157d-bbf7-469f-a291-6051d80af04c", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "a65254569ccf", + "error": null, + "generatedVideoId": "a65254569ccf" + }, + { + "id": "9d1937a1-e394-4ee3-a873-1b18332c8fe8", + "createdAt": 1789968219308, + "kind": "hd_render", + "sourceClipId": "ccaf964e04e4", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "73049ad1-13f9-4360-bf7e-46b89bcf9eef", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "e68a0e876c74", + "error": null, + "generatedVideoId": "e68a0e876c74" + }, + { + "id": "a4b2572f-b9d0-45c9-b606-eac15d1f5267", + "createdAt": 1789970912683, + "kind": "hd_render", + "sourceClipId": "ea82ada32190", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "c5b61a5c-98fe-4634-913c-7fdc4d7e653e", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "5b0641047b59", + "error": null, + "generatedVideoId": "5b0641047b59" + }, + { + "id": "6c410db1-d140-41a3-a033-9472767e6803", + "createdAt": 1789973927566, + "kind": "hd_render", + "sourceClipId": "4fc337764e2c", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "c1e9dcdc-41a3-4d48-afcf-65cf0e429820", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "0f0b36065adf", + "error": null, + "generatedVideoId": "0f0b36065adf" + }, + { + "id": "d7dc13c0-0fd8-4b68-bac6-5a2cfa971208", + "createdAt": 1789976711431, + "kind": "hd_render", + "sourceClipId": "7552751e4017", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "7d09a69b-2aa1-45af-b281-b10ff0db72ef", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "cec3f84055a6", + "error": null, + "generatedVideoId": "cec3f84055a6" + }, + { + "id": "48ab5ba0-a1ae-49d8-9dff-3bcc3b4c97c3", + "createdAt": 1789979628420, + "kind": "hd_render", + "sourceClipId": "ff818215fd3e", + "characterId": "35b3de40-82fb-4c4c-9f04-eef1a38972b2", + "garmentId": "7e4022ee-78d8-4b1d-b92a-eaf9022e4ac0", + "targetWidth": 768, + "targetHeight": 1344, + "status": "done", + "h3JobId": "8834f8b59b25", + "error": null, + "generatedVideoId": "8834f8b59b25" } ] \ No newline at end of file