fix: admin panel shows placeholder, error msg and URL for non-done videos
This commit is contained in:
@@ -57,6 +57,7 @@ class VideoInfo(BaseModel):
|
||||
file_size: int
|
||||
duration: int
|
||||
status: str
|
||||
error_message: str = ""
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
|
||||
@@ -24,16 +24,32 @@
|
||||
<div class="video-list">
|
||||
<div v-for="v in videos" :key="v.id" class="video-card">
|
||||
<div class="video-main">
|
||||
<!-- 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;
|
||||
|
||||
Reference in New Issue
Block a user