fix: admin panel shows placeholder, error msg and URL for non-done videos

This commit is contained in:
mini
2026-02-19 00:11:09 +08:00
parent 0299aea39b
commit 8e31c4b954
2 changed files with 61 additions and 7 deletions

View File

@@ -57,6 +57,7 @@ class VideoInfo(BaseModel):
file_size: int
duration: int
status: str
error_message: str = ""
created_at: datetime
class Config:

View File

@@ -24,16 +24,32 @@
<div class="video-list">
<div v-for="v in videos" :key="v.id" class="video-card">
<div class="video-main">
<img v-if="v.thumbnail" :src="v.thumbnail" class="thumb" />
<!-- Thumbnail or placeholder -->
<div class="thumb-wrap">
<img v-if="v.thumbnail" :src="v.thumbnail" class="thumb" />
<div v-else class="thumb-placeholder">
<span>{{ platformIcon(v.platform || v.url) }}</span>
</div>
<!-- Status overlay for active states -->
<div v-if="v.status === 'downloading'" class="thumb-overlay"></div>
<div v-else-if="v.status === 'pending'" class="thumb-overlay">🕐</div>
<div v-else-if="v.status === 'error'" class="thumb-overlay err-overlay"></div>
</div>
<div class="info">
<h4>{{ v.title || 'Untitled' }}</h4>
<h4 :title="v.title || v.url">{{ v.title || truncateUrl(v.url) }}</h4>
<div class="meta">
<span :class="'status-' + v.status">{{ v.status }}</span>
<span>{{ v.platform }}</span>
<span>{{ v.quality }}</span>
<span>{{ humanSize(v.file_size) }}</span>
<span :class="'status-badge status-' + v.status">{{ statusLabel(v.status) }}</span>
<span v-if="v.platform" class="platform-tag">{{ v.platform }}</span>
<span v-if="v.quality">{{ v.quality }}</span>
<span v-if="v.file_size">{{ humanSize(v.file_size) }}</span>
<span>{{ fmtTime(v.created_at) }}</span>
</div>
<!-- Error message -->
<div v-if="v.status === 'error' && v.error_message" class="error-msg" :title="v.error_message">
{{ v.error_message }}
</div>
<!-- URL for non-done -->
<div v-if="v.status !== 'done'" class="video-url">{{ v.url }}</div>
</div>
</div>
<div class="actions">
@@ -310,6 +326,23 @@ function fmtTime(ts) {
return new Date(ts).toLocaleString('zh-CN', { hour12: false })
}
function platformIcon(platformOrUrl) {
const s = (platformOrUrl || '').toLowerCase()
if (s.includes('youtube')) return '▶'
if (s.includes('pornhub')) return '🔞'
if (s.includes('twitter') || s.includes('x.com')) return '𝕏'
return '🎬'
}
function statusLabel(status) {
return { done: '✅ Done', downloading: '⏳ Downloading', pending: '🕐 Pending', error: '❌ Error', deleted: '🗑 Deleted' }[status] || status
}
function truncateUrl(url) {
if (!url) return 'Unknown'
try { return new URL(url).hostname + '...' } catch { return url.slice(0, 40) + '...' }
}
function browserIcon(b) {
return { Chrome: '🌐', Firefox: '🦊', Safari: '🧭', Edge: '🔷', Opera: '🔴', Samsung: '📱' }[b] || '🌐'
}
@@ -428,14 +461,34 @@ onMounted(() => { fetchVideos(); fetchStats() })
border: 1px solid #2a2a3e;
}
.video-main { display: flex; gap: 1.2rem; flex: 1; min-width: 0; }
.thumb { width: 112px; height: 63px; object-fit: cover; border-radius: 6px; flex-shrink: 0; }
.thumb-wrap { position: relative; flex-shrink: 0; width: 112px; height: 63px; }
.thumb { width: 112px; height: 63px; object-fit: cover; border-radius: 6px; }
.thumb-placeholder {
width: 112px; height: 63px; border-radius: 6px; background: #12122a;
border: 1px solid #333; display: flex; align-items: center; justify-content: center;
font-size: 1.6rem; color: #555;
}
.thumb-overlay {
position: absolute; inset: 0; border-radius: 6px;
background: rgba(0,0,0,0.55); display: flex; align-items: center; justify-content: center;
font-size: 1.3rem;
}
.err-overlay { background: rgba(180,0,0,0.45); }
.info { min-width: 0; }
.info h4 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 0.4rem; font-size: 1rem; }
.meta { display: flex; gap: 1rem; font-size: 0.88rem; color: #888; flex-wrap: wrap; }
.status-badge { font-size: 0.82rem; font-weight: 600; }
.status-done { color: #27ae60; }
.status-downloading { color: #f39c12; }
.status-error { color: #e74c3c; }
.status-pending { color: #888; }
.status-deleted { color: #555; }
.platform-tag { color: #1da1f2; font-size: 0.82rem; text-transform: capitalize; }
.error-msg {
color: #e74c3c; font-size: 0.8rem; margin-top: 0.3rem;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 500px;
}
.video-url { color: #555; font-size: 0.78rem; margin-top: 0.2rem; word-break: break-all; }
.actions { display: flex; gap: 0.4rem; flex-shrink: 0; }
.actions button, .actions a {
padding: 0.4rem 0.6rem; border: 1px solid #444; border-radius: 6px;