59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import { lookup } from 'mime-types'
|
|
import { createError, setHeader, sendStream } from 'h3'
|
|
const config = useRuntimeConfig()
|
|
const FOLDER_PATH = config.public.folder_path;
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const rawName = event.context.params?.name as string | undefined
|
|
if (!rawName) {
|
|
throw createError({ statusCode: 400, statusMessage: 'Nama file tidak diberikan' })
|
|
}
|
|
|
|
const name = decodeURIComponent(rawName)
|
|
const safeName = path.basename(name)
|
|
if (safeName !== name) {
|
|
throw createError({ statusCode: 400, statusMessage: 'Nama file tidak valid' })
|
|
}
|
|
|
|
const filePath = path.join(FOLDER_PATH, safeName)
|
|
if (!fs.existsSync(filePath)) {
|
|
throw createError({ statusCode: 404, statusMessage: 'File tidak ditemukan' })
|
|
}
|
|
|
|
// Ambil ekstensi file (lowercase)
|
|
const ext = path.extname(safeName).toLowerCase()
|
|
let mimeType = (lookup(safeName) as string) || 'application/octet-stream'
|
|
|
|
// Koreksi MIME type umum
|
|
switch (ext) {
|
|
case '.mp4':
|
|
mimeType = 'video/mp4'
|
|
break
|
|
case '.mkv':
|
|
mimeType = 'video/x-matroska'
|
|
break
|
|
case '.avi':
|
|
mimeType = 'video/x-msvideo'
|
|
break
|
|
case '.mov':
|
|
mimeType = 'video/quicktime'
|
|
break
|
|
case '.exe':
|
|
case '.msi':
|
|
mimeType = 'application/octet-stream'
|
|
break
|
|
case '.gif':
|
|
mimeType = 'image/gif'
|
|
break
|
|
}
|
|
|
|
setHeader(event, 'Content-Type', mimeType)
|
|
setHeader(event, 'Cache-Control', 'no-cache')
|
|
setHeader(event, 'Content-Disposition', `inline; filename="${safeName}"`)
|
|
|
|
const stream = fs.createReadStream(filePath)
|
|
return sendStream(event, stream)
|
|
})
|