add thumbnail generation
This commit is contained in:
62
src/app/api/thumbnail/route.ts
Normal file
62
src/app/api/thumbnail/route.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { getLibrary, resolveLibraryRoot, resolveAndJail } from '@/lib/libraries'
|
||||
import { getThumbnailPath } from '@/lib/thumbnails'
|
||||
|
||||
const VIDEO_EXTENSIONS = new Set(['.mp4', '.mov', '.mkv', '.avi', '.webm', '.m4v'])
|
||||
const IMAGE_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.tiff', '.tif'])
|
||||
|
||||
function getMediaType(filePath: string): 'image' | 'video' | null {
|
||||
const ext = path.extname(filePath).toLowerCase()
|
||||
if (IMAGE_EXTENSIONS.has(ext)) return 'image'
|
||||
if (VIDEO_EXTENSIONS.has(ext)) return 'video'
|
||||
return null
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const { searchParams } = request.nextUrl
|
||||
const libraryId = searchParams.get('libraryId')
|
||||
const subpath = searchParams.get('path')
|
||||
|
||||
if (!libraryId || !subpath) {
|
||||
return NextResponse.json({ error: 'Missing libraryId or path' }, { status: 400 })
|
||||
}
|
||||
|
||||
const library = getLibrary(libraryId)
|
||||
if (!library) {
|
||||
return NextResponse.json({ error: 'Library not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
const root = resolveLibraryRoot(library)
|
||||
|
||||
let filePath: string
|
||||
try {
|
||||
filePath = resolveAndJail(root, subpath)
|
||||
} catch {
|
||||
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
|
||||
}
|
||||
|
||||
const mediaType = getMediaType(filePath)
|
||||
if (!mediaType) {
|
||||
return NextResponse.json({ error: 'Thumbnails are only supported for image and video files' }, { status: 400 })
|
||||
}
|
||||
|
||||
try {
|
||||
const thumbnailPath = await getThumbnailPath(filePath, libraryId, mediaType)
|
||||
const stat = fs.statSync(thumbnailPath)
|
||||
const stream = fs.createReadStream(thumbnailPath)
|
||||
|
||||
return new NextResponse(stream as unknown as ReadableStream, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'image/jpeg',
|
||||
'Content-Length': String(stat.size),
|
||||
'Cache-Control': 'public, max-age=86400',
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(`Thumbnail generation failed for ${filePath}:`, err)
|
||||
return new NextResponse(null, { status: 404 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user