q6 commited on
Commit
f024bb3
·
1 Parent(s): 4e09fae

Refine reclass explorer detail

Browse files
Files changed (3) hide show
  1. backend/app.py +15 -2
  2. frontend/app.js +10 -7
  3. frontend/style.css +0 -16
backend/app.py CHANGED
@@ -1400,6 +1400,12 @@ async def start_reclass(req: ReclassRequest, bg: BackgroundTasks):
1400
  if not targets:
1401
  await finish_reclass_job(job_id, 0, [], 0, allowed)
1402
  return {"id": job_id, "status": "empty"}
 
 
 
 
 
 
1403
  bg.add_task(bg_reclass_task, job_id, targets, allowed, PHPSESSID)
1404
  return {"id": job_id, "status": "started", "total": len(targets)}
1405
 
@@ -1420,17 +1426,24 @@ async def get_reclass(job_id: str):
1420
  return {"error": "not found"}
1421
  row = rows[0]
1422
  summary = parse_json_maybe(cell_value(row, 6, "{}")) or {}
 
 
 
 
 
 
1423
  return {
1424
  "id": cell_value(row, 0, ""),
1425
  "kind": "reclass",
1426
  "post_ids": json.loads(cell_value(row, 1, "[]")),
1427
  "filters": json.loads(cell_value(row, 2, "[]")),
1428
- "total": int(cell_value(row, 3, "0")),
1429
- "scanned": int(cell_value(row, 4, "0")),
1430
  "changed": int(cell_value(row, 5, "0")),
1431
  "summary": summary,
1432
  "log": decrypt_log(cell_value(row, 7, "")),
1433
  "created_at": int(cell_value(row, 8, "0")),
 
1434
  }
1435
 
1436
 
 
1400
  if not targets:
1401
  await finish_reclass_job(job_id, 0, [], 0, allowed)
1402
  return {"id": job_id, "status": "empty"}
1403
+ ACTIVE_TASKS[job_id] = {
1404
+ "type": "reclass",
1405
+ "phase": "queued",
1406
+ "total": len(targets),
1407
+ "done": 0,
1408
+ }
1409
  bg.add_task(bg_reclass_task, job_id, targets, allowed, PHPSESSID)
1410
  return {"id": job_id, "status": "started", "total": len(targets)}
1411
 
 
1426
  return {"error": "not found"}
1427
  row = rows[0]
1428
  summary = parse_json_maybe(cell_value(row, 6, "{}")) or {}
1429
+ active = ACTIVE_TASKS.get(job_id)
1430
+ total = int(cell_value(row, 3, "0"))
1431
+ scanned = int(cell_value(row, 4, "0"))
1432
+ if active:
1433
+ total = int(active.get("total") or total)
1434
+ scanned = int(active.get("done") or scanned)
1435
  return {
1436
  "id": cell_value(row, 0, ""),
1437
  "kind": "reclass",
1438
  "post_ids": json.loads(cell_value(row, 1, "[]")),
1439
  "filters": json.loads(cell_value(row, 2, "[]")),
1440
+ "total": total,
1441
+ "scanned": scanned,
1442
  "changed": int(cell_value(row, 5, "0")),
1443
  "summary": summary,
1444
  "log": decrypt_log(cell_value(row, 7, "")),
1445
  "created_at": int(cell_value(row, 8, "0")),
1446
+ "active": active,
1447
  }
1448
 
1449
 
frontend/app.js CHANGED
@@ -16,6 +16,7 @@ let explorerDebounce = null
16
  let submittedSearchId = null
17
  let submittedFilterKey = null
18
  let resultCardCache = new Map()
 
19
 
20
 
21
  $$(".tab").forEach(tab => {
@@ -116,11 +117,13 @@ function route() {
116
  const id = decodeURIComponent(parts[1])
117
  openSearch(id, parseInt(params.get("page")) || 1, submittedSearchId === id)
118
  } else {
 
119
  resetSubmittedSearch()
120
  loadSearches(parseInt(params.get("page")) || 1)
121
  openExplorerEvents()
122
  }
123
  } else {
 
124
  closeExplorerEvents()
125
  }
126
  }
@@ -325,6 +328,7 @@ async function openSearch(id, page = 1, show = false) {
325
  $("#detail-stats").textContent = ""
326
  $("#pager").innerHTML = ""
327
  $("#results-grid").classList.remove("log-grid")
 
328
  if (!show) $("#results-grid").replaceChildren()
329
  $("#btn-back").onclick = () => { location.hash = "#/explorer" }
330
  const scanBtn = $("#btn-scan")
@@ -418,8 +422,8 @@ function renderReclassDetail(data) {
418
  $("#pager").innerHTML = ""
419
  $("#btn-scan").style.display = "none"
420
  const filters = (data.summary.filters || data.filters.map(code => CATEGORY_NAMES[code] || code)).join(", ")
421
- $("#detail-stats").textContent = `${data.changed}/${data.total} changed | ${data.scanned}/${data.total} scanned | ${filters}`
422
- const postIds = data.post_ids.map(pid => `<button class="post-id" data-pid="${esc(pid)}">${esc(pid)}</button>`).join("")
423
  const log = data.log.length
424
  ? data.log.map(item => `<div class="log-row">
425
  <span>${esc(item.post_id)}</span>
@@ -438,12 +442,11 @@ function renderReclassDetail(data) {
438
  <h2>Detailed log</h2>
439
  <div class="log-head"><span>Post ID</span><span>From</span><span>To</span></div>
440
  <div class="log-list">${log}</div>
441
- <h2>Post IDs</h2>
442
- <div class="post-id-list">${postIds}</div>
443
  </div>`
444
- $$(".post-id").forEach(btn => {
445
- btn.onclick = () => window.open(`https://www.pixiv.net/artworks/${btn.dataset.pid}`, "_blank")
446
- })
 
447
  }
448
 
449
  function pageSuffix(url) {
 
16
  let submittedSearchId = null
17
  let submittedFilterKey = null
18
  let resultCardCache = new Map()
19
+ let reclassDetailTimer = null
20
 
21
 
22
  $$(".tab").forEach(tab => {
 
117
  const id = decodeURIComponent(parts[1])
118
  openSearch(id, parseInt(params.get("page")) || 1, submittedSearchId === id)
119
  } else {
120
+ clearTimeout(reclassDetailTimer)
121
  resetSubmittedSearch()
122
  loadSearches(parseInt(params.get("page")) || 1)
123
  openExplorerEvents()
124
  }
125
  } else {
126
+ clearTimeout(reclassDetailTimer)
127
  closeExplorerEvents()
128
  }
129
  }
 
328
  $("#detail-stats").textContent = ""
329
  $("#pager").innerHTML = ""
330
  $("#results-grid").classList.remove("log-grid")
331
+ clearTimeout(reclassDetailTimer)
332
  if (!show) $("#results-grid").replaceChildren()
333
  $("#btn-back").onclick = () => { location.hash = "#/explorer" }
334
  const scanBtn = $("#btn-scan")
 
422
  $("#pager").innerHTML = ""
423
  $("#btn-scan").style.display = "none"
424
  const filters = (data.summary.filters || data.filters.map(code => CATEGORY_NAMES[code] || code)).join(", ")
425
+ const phase = data.active ? ` | ${data.active.phase}` : ""
426
+ $("#detail-stats").textContent = `${data.changed}/${data.total} changed | ${data.scanned}/${data.total} scanned | ${filters}${phase}`
427
  const log = data.log.length
428
  ? data.log.map(item => `<div class="log-row">
429
  <span>${esc(item.post_id)}</span>
 
442
  <h2>Detailed log</h2>
443
  <div class="log-head"><span>Post ID</span><span>From</span><span>To</span></div>
444
  <div class="log-list">${log}</div>
 
 
445
  </div>`
446
+ if (data.active) {
447
+ clearTimeout(reclassDetailTimer)
448
+ reclassDetailTimer = setTimeout(() => openSearch(data.id, 1, true), 2500)
449
+ }
450
  }
451
 
452
  function pageSuffix(url) {
frontend/style.css CHANGED
@@ -344,22 +344,6 @@ input:focus, select:focus { outline: none; border-color: var(--accent); backgrou
344
  border: 1px solid var(--line);
345
  border-radius: 6px;
346
  }
347
- .post-id-list {
348
- display: flex;
349
- flex-wrap: wrap;
350
- gap: .4rem;
351
- }
352
- .post-id {
353
- height: 30px;
354
- padding: 0 .55rem;
355
- background: #0b0d0f;
356
- border: 1px solid var(--line);
357
- border-radius: 6px;
358
- color: var(--accent);
359
- cursor: pointer;
360
- font-family: Consolas, "SFMono-Regular", monospace;
361
- }
362
- .post-id:hover { border-color: var(--accent); }
363
  .result-card {
364
  position: relative;
365
  min-width: 0;
 
344
  border: 1px solid var(--line);
345
  border-radius: 6px;
346
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  .result-card {
348
  position: relative;
349
  min-width: 0;