managarten/apps-archived/wisekeep/apps/web/src/lib/stores/jobs.ts
Till-JS 61d181fbc2 chore: archive inactive projects to apps-archived/
Move inactive projects out of active workspace:
- bauntown (community website)
- maerchenzauber (AI story generation)
- memoro (voice memo app)
- news (news aggregation)
- nutriphi (nutrition tracking)
- reader (reading app)
- uload (URL shortener)
- wisekeep (AI wisdom extraction)

Update CLAUDE.md documentation:
- Add presi to active projects
- Document archived projects section
- Update workspace configuration

Archived apps can be re-activated by moving back to apps/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 07:03:59 +01:00

107 lines
2.5 KiB
TypeScript

import { writable, derived, type Writable } from 'svelte/store';
import { browser } from '$app/environment';
import type { TranscriptionJob } from '$lib/api/client';
const API_URL = 'http://localhost:3006';
const WS_URL = API_URL.replace('http', 'ws');
export const jobs: Writable<Map<string, TranscriptionJob>> = writable(new Map());
export const isConnected = writable(false);
export const jobList = derived(jobs, ($jobs) =>
Array.from($jobs.values()).sort(
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
)
);
export const activeJobs = derived(jobList, ($jobs) =>
$jobs.filter(
(j) => j.status === 'pending' || j.status === 'downloading' || j.status === 'transcribing'
)
);
let socket: WebSocket | null = null;
let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
export function initWebSocket() {
if (!browser) return;
const connect = () => {
socket = new WebSocket(`${WS_URL}/progress`);
socket.onopen = () => {
console.log('[WebSocket] Connected');
isConnected.set(true);
};
socket.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.type === 'heartbeat') {
return;
}
if (
data.type === 'job_update' ||
data.type === 'job_complete' ||
data.type === 'job_error'
) {
jobs.update((map) => {
const existing = map.get(data.jobId);
if (existing) {
map.set(data.jobId, {
...existing,
status: data.status || existing.status,
progress: data.progress ?? existing.progress,
error: data.error || existing.error,
videoInfo: data.videoInfo || existing.videoInfo,
transcriptPath: data.transcriptPath || existing.transcriptPath,
});
}
return new Map(map);
});
}
} catch (e) {
console.error('[WebSocket] Parse error:', e);
}
};
socket.onclose = () => {
console.log('[WebSocket] Disconnected');
isConnected.set(false);
// Reconnect after 3 seconds
reconnectTimeout = setTimeout(connect, 3000);
};
socket.onerror = (error) => {
console.error('[WebSocket] Error:', error);
};
};
connect();
}
export function addJob(job: TranscriptionJob) {
jobs.update((map) => {
map.set(job.id, job);
return new Map(map);
});
}
export function removeJob(id: string) {
jobs.update((map) => {
map.delete(id);
return new Map(map);
});
}
export function cleanup() {
if (reconnectTimeout) {
clearTimeout(reconnectTimeout);
}
if (socket) {
socket.close();
}
}