Enhance audio processing capabilities: add FFmpeg for audio transcoding, update database schema, and improve UI for audio file uploads
This commit is contained in:
+33
-4
@@ -2,7 +2,7 @@ const DB_NAME = 'faerro-kb-local';
|
||||
const STORE_NAME = 'recordings';
|
||||
const MAX_RECORDING_MS = 30 * 60 * 1000;
|
||||
const elements = Object.fromEntries([
|
||||
'record-button', 'record-title', 'record-help', 'record-time', 'record-meter-fill', 'audio-level', 'audio-level-fill', 'capture-message',
|
||||
'record-button', 'record-title', 'record-help', 'record-time', 'record-meter-fill', 'audio-level', 'audio-level-fill', 'capture-message', 'audio-file-input',
|
||||
'queue-list', 'queue-empty', 'queue-count', 'sync-button', 'archive-list', 'archive-empty',
|
||||
'network-state', 'storage-status',
|
||||
].map((id) => [id, document.getElementById(id)]));
|
||||
@@ -53,7 +53,9 @@ function updateNetwork() {
|
||||
const online = navigator.onLine;
|
||||
elements['network-state'].classList.toggle('online', online);
|
||||
elements['network-state'].innerHTML = `<i></i>${online ? 'Connected' : 'Offline'}`;
|
||||
elements['storage-status'].textContent = online ? 'Pending audio stays here until server confirmation.' : 'Offline: new audio is saved on this device.';
|
||||
if (elements['storage-status']) {
|
||||
elements['storage-status'].textContent = online ? 'Pending audio stays here until server confirmation.' : 'Offline: new audio is saved on this device.';
|
||||
}
|
||||
}
|
||||
|
||||
function formatDuration(milliseconds) {
|
||||
@@ -170,7 +172,7 @@ async function saveRecording() {
|
||||
setMessage('No audio was captured. Please try again.', true);
|
||||
return;
|
||||
}
|
||||
const extension = blob.type.includes('webm') ? 'webm' : blob.type.includes('ogg') ? 'ogg' : 'm4a';
|
||||
const extension = blob.type.includes('webm') ? 'webm' : blob.type.includes('ogg') ? 'ogg' : blob.type.includes('mp4') ? 'm4a' : 'audio';
|
||||
const createdAt = new Date(recordingStartedAt).toISOString();
|
||||
const recording = {
|
||||
id: crypto.randomUUID(),
|
||||
@@ -190,6 +192,27 @@ async function saveRecording() {
|
||||
}
|
||||
}
|
||||
|
||||
async function queueAudioFile(file) {
|
||||
const createdAtMs = Date.now();
|
||||
const createdAt = new Date(createdAtMs).toISOString();
|
||||
const recording = {
|
||||
id: crypto.randomUUID(),
|
||||
blob: file,
|
||||
createdAt,
|
||||
filename: file.name,
|
||||
durationMs: 0,
|
||||
createdAtMs,
|
||||
};
|
||||
try {
|
||||
await putQueued(recording);
|
||||
setMessage(navigator.onLine ? 'Audio saved on device. Uploading now…' : 'Audio saved on device. It will upload when you reconnect.');
|
||||
await renderQueue();
|
||||
await syncQueue();
|
||||
} catch {
|
||||
setMessage('Could not save this file in browser storage. Check available device storage and try again.', true);
|
||||
}
|
||||
}
|
||||
|
||||
async function syncQueue() {
|
||||
if (syncing || !navigator.onLine) return;
|
||||
syncing = true;
|
||||
@@ -247,7 +270,7 @@ async function renderQueue() {
|
||||
status.textContent = navigator.onLine ? 'WAITING TO SYNC' : 'SAVED OFFLINE';
|
||||
const meta = document.createElement('div');
|
||||
meta.className = 'item-meta';
|
||||
meta.textContent = `${prettyDate(recording.createdAt)} · ${formatDuration(recording.durationMs)}`;
|
||||
meta.textContent = `${prettyDate(recording.createdAt)}${recording.durationMs ? ` · ${formatDuration(recording.durationMs)}` : ''}`;
|
||||
const remove = createDeleteButton(`Delete queued note ${recording.filename}`);
|
||||
remove.disabled = syncing;
|
||||
remove.addEventListener('click', async () => {
|
||||
@@ -355,6 +378,12 @@ async function loadAwaitingNotes() {
|
||||
}
|
||||
|
||||
elements['record-button'].addEventListener('click', () => mediaRecorder?.state === 'recording' ? stopRecording() : startRecording());
|
||||
elements['audio-file-input'].addEventListener('change', async (event) => {
|
||||
const [file] = event.target.files;
|
||||
if (file) await queueAudioFile(file);
|
||||
event.target.value = '';
|
||||
});
|
||||
elements['sync-button'].addEventListener('click', syncQueue);
|
||||
elements['sync-button'].addEventListener('click', syncQueue);
|
||||
window.addEventListener('online', () => { updateNetwork(); syncQueue(); loadAwaitingNotes(); });
|
||||
window.addEventListener('offline', updateNetwork);
|
||||
|
||||
Reference in New Issue
Block a user