打包构建

This commit is contained in:
Yeomai committed 2026-10-18 16:17:01 +08:00
1 parent a6e45e0cb1
commit ee8772c1b7
36 files changed
+940 -21

No files matched your search

+3
View File
@@ -120,6 +120,9 @@ export async function handleFileList(
...(stored.transcodeStartedAt
? { transcodeStartedAt: stored.transcodeStartedAt }
: {}),
...(typeof stored.transcodeDurationMs === 'number'
? { transcodeDurationMs: stored.transcodeDurationMs }
: {}),
...(stored.sourceDeleted ? { sourceDeleted: true } : {}),
...(stored.thumbKey
? { thumbUrl: resolveImageUrl(event, stored.thumbKey, stored.backendId) }
+13 -8
View File
@@ -48,6 +48,7 @@ export interface ImageIndexRow {
transcode_preset: string | null
transcode_error: string | null
transcode_started_at: string | null
transcode_duration_ms: number | null
}
function keyToFilePath(key: string): string {
@@ -82,6 +83,7 @@ function rowToStoredImage(row: ImageIndexRow): StoredImage {
transcodePreset: row.transcode_preset ?? null,
transcodeError: row.transcode_error ?? null,
transcodeStartedAt: row.transcode_started_at ?? null,
transcodeDurationMs: row.transcode_duration_ms ?? null,
mtimeMs: Number.isFinite(uploadedMs) ? uploadedMs : Date.now()
}
}
@@ -236,7 +238,7 @@ export async function purgeOrphanImageIndexRows(): Promise<number> {
export function getImageIndexRow(key: string): ImageIndexRow | null {
ensureStorageSchema()
const row = getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE key = ?
`).get(key) as ImageIndexRow | undefined
@@ -429,7 +431,7 @@ export function getImageTotals(): { count: number, bytes: number } {
export function listAllImageIndexRows(): ImageIndexRow[] {
ensureStorageSchema()
return getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
ORDER BY key ASC
`).all() as unknown as ImageIndexRow[]
@@ -441,7 +443,7 @@ export function listImageIndexRowsAfter(
): ImageIndexRow[] {
ensureStorageSchema()
return getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE key > ?
ORDER BY key ASC
@@ -452,7 +454,7 @@ export function listImageIndexRowsAfter(
export function listImageIndexRowsForUser(userId: number): ImageIndexRow[] {
ensureStorageSchema()
return getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE user_id = ?
ORDER BY key ASC
@@ -462,7 +464,7 @@ export function listImageIndexRowsForUser(userId: number): ImageIndexRow[] {
export function listImageIndexRowsByBackend(backendId: string): ImageIndexRow[] {
ensureStorageSchema()
return getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE backend_id = ?
ORDER BY key ASC
@@ -488,6 +490,7 @@ export function updateImageTranscode(
preset?: string | null
error?: string | null
startedAt?: string | null
durationMs?: number | null
}
): void {
ensureStorageSchema()
@@ -501,6 +504,7 @@ export function updateImageTranscode(
transcode_preset = COALESCE(?, transcode_preset),
transcode_error = ?,
transcode_started_at = COALESCE(?, transcode_started_at)
, transcode_duration_ms = COALESCE(?, transcode_duration_ms)
WHERE key = ?
`).run(
input.status,
@@ -511,6 +515,7 @@ export function updateImageTranscode(
input.preset ?? null,
input.error ?? null,
input.startedAt ?? null,
input.durationMs ?? null,
key
)
}
@@ -708,7 +713,7 @@ export async function listImages(options: {
const backendSql = buildBackendFilterSql(options.backendId, params)
const tagSql = buildTagFilterSql(options.tagFilter, params)
const rows = getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE ${clauses.join(' AND ')}${userSql}${backendSql}${tagSql}
ORDER BY uploaded_at DESC, key DESC
@@ -754,7 +759,7 @@ export async function searchImages(options: {
const backendSql = buildBackendFilterSql(options.backendId, params)
const tagSql = buildTagFilterSql(options.tagFilter, params)
const rows = getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE ${clauses.join(' AND ')}${userSql}${backendSql}${tagSql}
ORDER BY uploaded_at DESC, key DESC
@@ -888,7 +893,7 @@ export async function getUserScopedStorageStats(
export async function listImageKeysForAutoDelete(): Promise<StoredImage[]> {
ensureStorageSchema()
const rows = getDb().prepare(`
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_error
SELECT key, backend_id, user_id, folder, media_type, original_name, content_type, size, uploaded_at, hls_key, transcode_status, transcode_progress, thumb_key, source_deleted, transcode_preset, transcode_started_at, transcode_duration_ms, transcode_error
FROM images
WHERE media_type = 'image'
ORDER BY uploaded_at ASC
+2 -1
View File
@@ -20,7 +20,8 @@ const row: ImageIndexRow = {
source_deleted: 0,
transcode_preset: 'veryfast',
transcode_error: null,
transcode_started_at: null
transcode_started_at: null,
transcode_duration_ms: null
}
async function createBackend() {
+24
View File
@@ -96,6 +96,7 @@ const STORAGE_SCHEMA_SOURCE_DELETED_KEY = 'storage_schema_source_deleted'
const STORAGE_SCHEMA_TRANSCODE_PRESET_KEY = 'storage_schema_transcode_preset'
const STORAGE_SCHEMA_TRANSCODE_ERROR_KEY = 'storage_schema_transcode_error'
const STORAGE_SCHEMA_TRANSCODE_STARTED_KEY = 'storage_schema_transcode_started'
const STORAGE_SCHEMA_TRANSCODE_DURATION_KEY = 'storage_schema_transcode_duration'
/** images 表新增 media_type 列(区分图床图片与文件床文件) */
function migrateImagesMediaType(database: DatabaseSync): void {
@@ -276,6 +277,27 @@ function migrateImagesTranscodeStarted(database: DatabaseSync): void {
`).run(STORAGE_SCHEMA_TRANSCODE_STARTED_KEY, new Date().toISOString())
}
/** images 表新增「转码总耗时」列 */
function migrateImagesTranscodeDuration(database: DatabaseSync): void {
const migrated = database.prepare(`
SELECT value FROM settings WHERE key = ?
`).get(STORAGE_SCHEMA_TRANSCODE_DURATION_KEY) as { value?: string } | undefined
if (migrated?.value === '1') return
const columns = database.prepare('PRAGMA table_info(images)').all() as Array<{
name: string
}>
if (!columns.some(column => column.name === 'transcode_duration_ms')) {
database.exec('ALTER TABLE images ADD COLUMN transcode_duration_ms INTEGER')
}
database.prepare(`
INSERT OR REPLACE INTO settings (key, value, updated_at)
VALUES (?, '1', ?)
`).run(STORAGE_SCHEMA_TRANSCODE_DURATION_KEY, new Date().toISOString())
}
function migrateStorageTables(database: DatabaseSync): void {
database.exec(`
CREATE TABLE IF NOT EXISTS storage_backends (
@@ -309,6 +331,7 @@ function migrateStorageTables(database: DatabaseSync): void {
transcode_preset TEXT,
transcode_error TEXT,
transcode_started_at TEXT,
transcode_duration_ms INTEGER,
FOREIGN KEY (backend_id) REFERENCES storage_backends(id)
);
CREATE INDEX IF NOT EXISTS idx_images_uploaded_at ON images(uploaded_at DESC);
@@ -332,6 +355,7 @@ function migrateStorageTables(database: DatabaseSync): void {
migrateImagesTranscodePreset(database)
migrateImagesTranscodeError(database)
migrateImagesTranscodeStarted(database)
migrateImagesTranscodeDuration(database)
database.exec(`
CREATE INDEX IF NOT EXISTS idx_images_media_type ON images(media_type);
`)
+2
View File
@@ -27,6 +27,8 @@ export interface StoredImage extends StoredImageMeta {
transcodePreset?: string | null
/** 转码开始时间(ISO) */
transcodeStartedAt?: string | null
/** 转码总耗时(毫秒),结束后固定 */
transcodeDurationMs?: number | null
/** 转码失败原因 */
transcodeError?: string | null
/** 视频封面缩略图 key */
+12 -3
View File
@@ -705,11 +705,14 @@ let activeCount = 0
async function processOne(job: QueuedTranscode): Promise<void> {
const { videoKey } = job
const startedAtIso = new Date().toISOString()
updateImageTranscode(videoKey, {
status: 'running',
startedAt: new Date().toISOString()
startedAt: startedAtIso
})
const elapsedMs = () => Math.max(0, Date.now() - new Date(startedAtIso).getTime())
try {
const { playlistKey, totalBytes } = await transcodeVideoToHls(videoKey, job)
@@ -722,13 +725,19 @@ async function processOne(job: QueuedTranscode): Promise<void> {
hlsKey: playlistKey,
progress: 100,
sourceDeleted: true,
size: totalBytes
size: totalBytes,
// 结束后清空计时起点,前端不再显示耗时
startedAt: '',
durationMs: elapsedMs()
})
logInfo('transcode done', { key: videoKey, hlsKey: playlistKey })
} catch (error) {
updateImageTranscode(videoKey, {
status: 'failed',
error: summarizeTranscodeFailure(error)
error: summarizeTranscodeFailure(error),
// 失败同样停止计时
startedAt: '',
durationMs: elapsedMs()
})
logException('transcode failed', error, { key: videoKey })
}