Initial commit: Tonemark PWA
Some checks failed
Build & Push Docker Image / build-and-push (push) Failing after 11s
Some checks failed
Build & Push Docker Image / build-and-push (push) Failing after 11s
Tonemark is a SvelteKit PWA for transcribing YouTube videos, audio and video files, and microphone recordings using a local Whisper backend. Features: - Dark glassmorphic UI with electric-lime accent (5 switchable themes) - Rail nav (desktop) / tab bar (mobile) layout - Drop zone, YouTube URL input, and live audio recording inputs - Audio mode waveform cards (none / standard / aggressive / auto) - Real-time transcription progress with animated waveform - Job queue with SSE streaming updates - Push notifications on job completion - PWA with native SvelteKit service worker - SRT / TXT / MD / JSON transcript downloads Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
54
src/routes/api/webhook/[jobId]/+server.ts
Normal file
54
src/routes/api/webhook/[jobId]/+server.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import { getJob, updateJob, setJobStatus } from '$lib/server/db.js';
|
||||
import { deduplicateSegments } from '$lib/server/postprocess.js';
|
||||
import { writeOutputs } from '$lib/server/formatter.js';
|
||||
import { sendNotification } from '$lib/server/push.js';
|
||||
import { cleanupJobTmp } from '$lib/server/downloader.js';
|
||||
import { emitProgress } from '$lib/server/pipeline.js';
|
||||
import type { Segment, WhisperJob } from '$lib/types.js';
|
||||
|
||||
export async function POST({ params, request }) {
|
||||
const jobId = params.jobId;
|
||||
const job = getJob(jobId);
|
||||
if (!job) throw error(404, 'Job not found');
|
||||
|
||||
const whisperJob = (await request.json()) as WhisperJob;
|
||||
|
||||
if (whisperJob.status === 'failed' || whisperJob.status === 'cancelled') {
|
||||
const msg = whisperJob.error ?? `Whisper job ${whisperJob.status}`;
|
||||
updateJob({ id: jobId, status: 'failed', error: msg });
|
||||
emitProgress(jobId, { type: 'error', message: msg });
|
||||
return json({ ok: true });
|
||||
}
|
||||
|
||||
try {
|
||||
setJobStatus(jobId, 'processing', 90);
|
||||
emitProgress(jobId, { type: 'status', status: 'processing', progress: 90 });
|
||||
|
||||
const rawSegments = whisperJob.segments as Segment[];
|
||||
const segments = deduplicateSegments(rawSegments);
|
||||
|
||||
const paths = await writeOutputs(segments, job.title, jobId);
|
||||
const outputDir = paths.srt.replace(/\/[^/]+$/, '');
|
||||
|
||||
updateJob({
|
||||
id: jobId,
|
||||
status: 'done',
|
||||
progress: 100,
|
||||
segmentsJson: JSON.stringify(segments),
|
||||
outputDir
|
||||
});
|
||||
|
||||
emitProgress(jobId, { type: 'done', status: 'done' });
|
||||
|
||||
await sendNotification(jobId, '✅ Transcript ready', job.title);
|
||||
await cleanupJobTmp(jobId);
|
||||
|
||||
return json({ ok: true });
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
updateJob({ id: jobId, status: 'failed', error: message });
|
||||
emitProgress(jobId, { type: 'error', message });
|
||||
return json({ ok: false, error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user