Template
feat: fetch and backfill cover art
This commit is contained in:
@@ -19,6 +19,9 @@ export interface IngestStatusResponse {
|
||||
lyricsFound: number;
|
||||
lyricsMissing: number;
|
||||
lyricsFailed: number;
|
||||
coversFound: number;
|
||||
coversMissing: number;
|
||||
coversFailed: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,12 @@ export interface ProgressMessage {
|
||||
unreadableFiles?: number;
|
||||
conversionFailedFiles?: number;
|
||||
otherRejectedFiles?: number;
|
||||
lyricsFound?: number;
|
||||
lyricsMissing?: number;
|
||||
lyricsFailed?: number;
|
||||
coversFound?: number;
|
||||
coversMissing?: number;
|
||||
coversFailed?: number;
|
||||
}
|
||||
|
||||
export function getProgress(taskId: string): Promise<ProgressMessage | null> {
|
||||
|
||||
@@ -215,6 +215,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 封面统计 -->
|
||||
<div class="stats-grid stats-secondary lyric-stats">
|
||||
<div class="stat-cell-sm"><span class="stat-name-sm">有封面</span><span class="stat-num-sm">{{ coverStats.found }}</span></div>
|
||||
<div class="stat-cell-sm"><span class="stat-name-sm">无封面</span><span class="stat-num-sm">{{ coverStats.missing }}</span></div>
|
||||
<div class="stat-cell-sm"><span class="stat-name-sm">封面失败</span><span class="stat-num-sm">{{ coverStats.failed }}</span></div>
|
||||
</div>
|
||||
<!-- 歌词统计(歌词有无绝不影响音频入库,仅观测) -->
|
||||
<div class="stats-grid stats-secondary lyric-stats">
|
||||
<div class="stat-cell-sm">
|
||||
@@ -339,6 +345,19 @@ import { useWebSocket } from '../composables/useWebSocket';
|
||||
import type { ProgressMessage } from '../composables/useWebSocket';
|
||||
import { useAppState } from '../composables/useAppState';
|
||||
|
||||
interface IngestProgressMessage extends ProgressMessage {
|
||||
lyricsFound?: number;
|
||||
lyricsMissing?: number;
|
||||
lyricsFailed?: number;
|
||||
coversFound?: number;
|
||||
coversMissing?: number;
|
||||
coversFailed?: number;
|
||||
}
|
||||
|
||||
function isIngestMessage(msg: ProgressMessage): msg is IngestProgressMessage {
|
||||
return msg.type === 'ingest' || 'coversFound' in msg || 'lyricsFound' in msg;
|
||||
}
|
||||
|
||||
const {
|
||||
state: appState,
|
||||
isConfigured,
|
||||
@@ -380,22 +399,27 @@ const canStart = computed(() => isConfigured.value && !submitting.value);
|
||||
* 歌词统计(独立于 ProgressMessage 类型,避免修改共享类型)。
|
||||
* 歌词的有/无/失败绝不影响音频入库,仅作观测展示。
|
||||
*/
|
||||
const coverStats = reactive<{ found: number; missing: number; failed: number }>({ found: 0, missing: 0, failed: 0 });
|
||||
const lyricStats = reactive<{ found: number; missing: number; failed: number }>({
|
||||
found: 0,
|
||||
missing: 0,
|
||||
failed: 0
|
||||
});
|
||||
|
||||
type LyricCarrier = { lyricsFound?: number; lyricsMissing?: number; lyricsFailed?: number };
|
||||
function applyLyricStats(src: ProgressMessage | null | undefined) {
|
||||
if (!src || !isIngestMessage(src)) return;
|
||||
|
||||
function applyLyricStats(src: LyricCarrier | null | undefined) {
|
||||
if (!src) return;
|
||||
if (typeof src.lyricsFound === 'number') lyricStats.found = src.lyricsFound;
|
||||
if (typeof src.lyricsMissing === 'number') lyricStats.missing = src.lyricsMissing;
|
||||
if (typeof src.lyricsFailed === 'number') lyricStats.failed = src.lyricsFailed;
|
||||
|
||||
if (typeof src.coversFound === 'number') coverStats.found = src.coversFound;
|
||||
if (typeof src.coversMissing === 'number') coverStats.missing = src.coversMissing;
|
||||
if (typeof src.coversFailed === 'number') coverStats.failed = src.coversFailed;
|
||||
}
|
||||
|
||||
function resetLyricStats() {
|
||||
coverStats.found = 0; coverStats.missing = 0; coverStats.failed = 0;
|
||||
lyricStats.found = 0;
|
||||
lyricStats.missing = 0;
|
||||
lyricStats.failed = 0;
|
||||
@@ -600,7 +624,7 @@ async function scrollConsoleIfPinned() {
|
||||
|
||||
function handleProgressMessage(msg: ProgressMessage) {
|
||||
Object.assign(progress, msg);
|
||||
applyLyricStats(msg as unknown as LyricCarrier);
|
||||
applyLyricStats(msg);
|
||||
recordActivity(msg);
|
||||
|
||||
if (typeof msg.running === 'boolean') {
|
||||
@@ -619,7 +643,7 @@ const { connect: wsConnect, disconnect: wsDisconnect } = useWebSocket(taskId, ha
|
||||
|
||||
let pollTimer: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
function statusToProgress(resp: IngestStatusResponse): ProgressMessage {
|
||||
function statusToProgress(resp: IngestStatusResponse): IngestProgressMessage {
|
||||
return {
|
||||
taskId: resp.taskId,
|
||||
type: 'ingest',
|
||||
@@ -636,7 +660,13 @@ function statusToProgress(resp: IngestStatusResponse): ProgressMessage {
|
||||
missingMetadataFiles: resp.missingMetadataFiles,
|
||||
unreadableFiles: resp.unreadableFiles,
|
||||
conversionFailedFiles: resp.conversionFailedFiles,
|
||||
otherRejectedFiles: resp.otherRejectedFiles
|
||||
otherRejectedFiles: resp.otherRejectedFiles,
|
||||
lyricsFound: resp.lyricsFound,
|
||||
lyricsMissing: resp.lyricsMissing,
|
||||
lyricsFailed: resp.lyricsFailed,
|
||||
coversFound: resp.coversFound,
|
||||
coversMissing: resp.coversMissing,
|
||||
coversFailed: resp.coversFailed
|
||||
};
|
||||
}
|
||||
|
||||
@@ -647,7 +677,6 @@ function startPolling() {
|
||||
try {
|
||||
const resp = await getIngestStatus(taskId.value);
|
||||
if (resp) {
|
||||
applyLyricStats(resp);
|
||||
handleProgressMessage(statusToProgress(resp));
|
||||
if (resp.completed || !resp.running) {
|
||||
stopPolling();
|
||||
|
||||
Reference in New Issue
Block a user