first working demo

This commit is contained in:
2025-07-22 17:03:36 +02:00
parent f58e9ef5a2
commit b084910dc0
52 changed files with 11455 additions and 138 deletions

View File

@@ -0,0 +1,156 @@
import { fail } from '@sveltejs/kit';
import { db } from '$lib/server/db/index.js';
import { audioFile } from '$lib/server/db/schema.js';
import { eq, isNull } from 'drizzle-orm';
import { uploadToS3, deleteFromS3, generateAudioS3Key } from '$lib/server/s3.js';
export async function load() {
const audioFiles = await db.select({
id: audioFile.id,
filename: audioFile.filename,
contentType: audioFile.contentType,
duration: audioFile.duration,
fileSize: audioFile.fileSize,
createdAt: audioFile.createdAt
})
.from(audioFile)
.where(isNull(audioFile.deletedAt)); // Only show active audio files
return {
audioFiles
};
}
export const actions = {
upload: async ({ request }) => {
const data = await request.formData();
const file = data.get('audioFile');
if (!file || file.size === 0) {
return fail(400, {
missing: true
});
}
if (!file.type.startsWith('audio/')) {
return fail(400, {
invalidType: true
});
}
const id = crypto.randomUUID();
const buffer = Buffer.from(await file.arrayBuffer());
const s3Key = generateAudioS3Key(id, file.name);
try {
// Upload to S3 first
await uploadToS3(s3Key, buffer, file.type);
// Then save metadata to database (without blob data)
await db.insert(audioFile).values({
id,
filename: file.name,
contentType: file.type,
s3Key,
duration: null, // Will be updated by client-side after upload
fileSize: file.size,
createdAt: new Date()
});
return {
success: true
};
} catch (error) {
console.error('Error uploading audio file:', error);
return fail(500, {
error: error.message || 'Upload failed'
});
}
},
delete: async ({ request }) => {
const data = await request.formData();
const fileId = data.get('fileId');
if (!fileId) {
return fail(400, {
missing: true
});
}
try {
// Soft delete from database (don't delete from S3 for recovery purposes)
await db
.update(audioFile)
.set({ deletedAt: new Date() })
.where(eq(audioFile.id, fileId));
return {
deleted: true
};
} catch (error) {
console.error('Error deleting audio file:', error);
return fail(500, {
error: true
});
}
},
updateDuration: async ({ request }) => {
const data = await request.formData();
const fileId = data.get('fileId');
const duration = parseFloat(data.get('duration'));
if (!fileId || isNaN(duration)) {
return fail(400, {
missing: true
});
}
try {
await db.update(audioFile)
.set({ duration })
.where(eq(audioFile.id, fileId));
return {
success: true
};
} catch (error) {
console.error('Error updating duration:', error);
return fail(500, {
error: true
});
}
},
renameAudioFile: async ({ request }) => {
const data = await request.formData();
const audioFileId = data.get('audioFileId');
const newFilename = data.get('newFilename');
if (!audioFileId || !newFilename) {
return fail(400, { error: 'Invalid data provided' });
}
// Validate filename
const filename = newFilename.trim();
if (filename.length === 0) {
return fail(400, { error: 'Filename cannot be empty' });
}
if (filename.length > 255) {
return fail(400, { error: 'Filename is too long' });
}
try {
await db
.update(audioFile)
.set({ filename })
.where(eq(audioFile.id, audioFileId));
return { renamed: true, filename };
} catch (error) {
console.error('Error renaming audio file:', error);
return fail(500, { error: 'Failed to rename audio file' });
}
}
};