refactor(ingest): per-post handling into run stdout via a downloader outcome (#842)
Two corrections from operator review: 1. Reuse the existing 'Raw stdout' panel instead of a bespoke structured UI section — the native ingester now writes a per-post line into the run stdout (parity with gallery-dl's per-file stdout), so the per-post handling shows in the panel the operator already uses. 2. DRY: stop re-reading post['attributes'] inline in ingest_core. write_post_record now returns a PostRecordOutcome (path, post_type, title, body_chars) — mirroring the download_post -> MediaOutcome contract — and the downloader owns the read; ingest_core only formats the outcome into the log line. Reverts the post_diagnostics metadata field + DownloadDetailModal 'Post capture' section added earlier. Per-post line: 'post <id> [<post_type>] body: N chars' (+ ' — EMPTY' when 0), so an empty body is self-explanatory by post_type. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -28,54 +28,6 @@
|
||||
<div><span class="fc-dl-grid__label">Errors</span><span>{{ summary.errors ?? 0 }}</span></div>
|
||||
</div>
|
||||
|
||||
<template v-if="postDiag.length">
|
||||
<h3 class="text-subtitle-2 mt-4">Post capture</h3>
|
||||
<div class="fc-dl-grid">
|
||||
<div><span class="fc-dl-grid__label">Posts</span><span>{{ postDiag.length }}</span></div>
|
||||
<div><span class="fc-dl-grid__label">With body</span><span>{{ postWithBody }}</span></div>
|
||||
<div><span class="fc-dl-grid__label">Empty body</span><span>{{ postEmpty.length }}</span></div>
|
||||
</div>
|
||||
<v-expansion-panels class="mt-2">
|
||||
<v-expansion-panel v-if="postEmpty.length">
|
||||
<v-expansion-panel-title>
|
||||
<span>Empty-body posts ({{ postEmpty.length }})</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<table class="fc-dl-table">
|
||||
<thead><tr><th>Post</th><th>Type</th><th>Chars</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="p in postEmpty" :key="p.post_id" class="fc-dl-empty">
|
||||
<td>{{ p.title || `#${p.post_id}` }}</td>
|
||||
<td><code>{{ p.post_type || '—' }}</code></td>
|
||||
<td>{{ p.body_chars }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>
|
||||
<span>All posts ({{ postDiag.length }})</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<table class="fc-dl-table">
|
||||
<thead><tr><th>Post</th><th>Type</th><th>Chars</th></tr></thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="p in postDiag" :key="p.post_id"
|
||||
:class="{ 'fc-dl-empty': !p.body_chars }"
|
||||
>
|
||||
<td>{{ p.title || `#${p.post_id}` }}</td>
|
||||
<td><code>{{ p.post_type || '—' }}</code></td>
|
||||
<td>{{ p.body_chars }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
|
||||
<template v-if="quarantinedPaths.length">
|
||||
<h3 class="text-subtitle-2 mt-4">Quarantined paths</h3>
|
||||
<ul class="fc-dl-quar">
|
||||
@@ -163,31 +115,18 @@ const summary = computed(() => props.event?.metadata?.import_summary || {})
|
||||
const quarantinedPaths = computed(() => props.event?.metadata?.quarantined_paths || [])
|
||||
const errorsWarnings = computed(() => props.event?.metadata?.stderr_errors_warnings || '')
|
||||
|
||||
// #842: per-post body-capture diagnostics — how each post was handled, with
|
||||
// post_type so an empty body is self-explanatory in the UI.
|
||||
const postDiag = computed(() => props.event?.metadata?.post_diagnostics || [])
|
||||
const postEmpty = computed(() => postDiag.value.filter((p) => !p.body_chars))
|
||||
const postWithBody = computed(() => postDiag.value.length - postEmpty.value.length)
|
||||
|
||||
// One combined block for "research the issue elsewhere" — header line +
|
||||
// error + full stdout/stderr. Built lazily from the current event.
|
||||
const allDiagnostics = computed(() => {
|
||||
const e = props.event
|
||||
if (!e) return ''
|
||||
const md = e.metadata || {}
|
||||
const emptyPosts = postEmpty.value
|
||||
.map((p) => ` • ${p.title || '#' + p.post_id} [${p.post_type || '—'}] ${p.body_chars} chars`)
|
||||
.join('\n')
|
||||
return [
|
||||
`event #${e.id} · ${e.platform || '—'} · ${e.artist_name || '—'}`,
|
||||
`status: ${e.status}`,
|
||||
`started: ${e.started_at} finished: ${e.finished_at || '(running)'}`,
|
||||
e.error ? `\n--- error ---\n${e.error}` : '',
|
||||
errorsWarnings.value ? `\n--- errors & warnings ---\n${errorsWarnings.value}` : '',
|
||||
postDiag.value.length
|
||||
? `\n--- post capture (${postWithBody.value}/${postDiag.value.length} with body) ---`
|
||||
+ (emptyPosts ? `\nempty-body posts:\n${emptyPosts}` : '')
|
||||
: '',
|
||||
`\n--- stdout ---\n${md.stdout || '(empty)'}`,
|
||||
`\n--- stderr ---\n${md.stderr || '(empty)'}`,
|
||||
].filter(Boolean).join('\n')
|
||||
@@ -242,25 +181,6 @@ function onClose() {
|
||||
word-break: break-all;
|
||||
}
|
||||
.fc-dl-quar { padding-left: 1.5rem; font-size: 0.85rem; }
|
||||
.fc-dl-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.fc-dl-table th,
|
||||
.fc-dl-table td {
|
||||
text-align: left;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-bottom: 1px solid rgb(var(--v-theme-on-surface-variant) / 0.14);
|
||||
}
|
||||
.fc-dl-table th:last-child,
|
||||
.fc-dl-table td:last-child {
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.fc-dl-table .fc-dl-empty {
|
||||
color: rgb(var(--v-theme-warning));
|
||||
}
|
||||
.fc-dl-blockhead {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
|
||||
Reference in New Issue
Block a user