fix: improve file path handling in API routes

- Updated file reading and database querying logic to decode URL-encoded paths, ensuring proper handling of special characters.
- Refactored path usage in the GET requests for both media file listing and content retrieval, enhancing compatibility with various file names.
This commit is contained in:
tigeren 2025-09-02 17:14:32 +00:00
parent 89930b833c
commit fbeed219fc
3 changed files with 21 additions and 15 deletions

Binary file not shown.

View File

@ -13,20 +13,23 @@ export async function GET(request: Request) {
return NextResponse.json({ error: "Path is required" }, { status: 400 }); return NextResponse.json({ error: "Path is required" }, { status: 400 });
} }
// Decode the URL-encoded path to handle special characters
const decodedFilePath = decodeURIComponent(filePath);
try { try {
// Validate file exists // Validate file exists
if (!fs.existsSync(filePath)) { if (!fs.existsSync(decodedFilePath)) {
return NextResponse.json({ error: "File not found" }, { status: 404 }); return NextResponse.json({ error: "File not found" }, { status: 404 });
} }
// Check if it's a file (not directory) // Check if it's a file (not directory)
const stats = fs.statSync(filePath); const stats = fs.statSync(decodedFilePath);
if (!stats.isFile()) { if (!stats.isFile()) {
return NextResponse.json({ error: "Path is not a file" }, { status: 400 }); return NextResponse.json({ error: "Path is not a file" }, { status: 400 });
} }
// Check if it's a text file // Check if it's a text file
const ext = path.extname(filePath).toLowerCase().replace('.', ''); const ext = path.extname(decodedFilePath).toLowerCase().replace('.', '');
if (!TEXT_EXTENSIONS.includes(ext)) { if (!TEXT_EXTENSIONS.includes(ext)) {
return NextResponse.json({ error: "File type not supported" }, { status: 400 }); return NextResponse.json({ error: "File type not supported" }, { status: 400 });
} }
@ -41,10 +44,10 @@ export async function GET(request: Request) {
let content = ''; let content = '';
try { try {
if (encoding === 'utf8') { if (encoding === 'utf8') {
content = fs.readFileSync(filePath, 'utf-8'); content = fs.readFileSync(decodedFilePath, 'utf-8');
} else { } else {
// For non-UTF-8 encodings, read as buffer and convert // For non-UTF-8 encodings, read as buffer and convert
const buffer = fs.readFileSync(filePath); const buffer = fs.readFileSync(decodedFilePath);
const iconv = require('iconv-lite'); const iconv = require('iconv-lite');
content = iconv.decode(buffer, encoding); content = iconv.decode(buffer, encoding);
} }
@ -55,9 +58,9 @@ export async function GET(request: Request) {
for (const fallbackEncoding of fallbackEncodings) { for (const fallbackEncoding of fallbackEncodings) {
try { try {
if (fallbackEncoding === 'utf8') { if (fallbackEncoding === 'utf8') {
content = fs.readFileSync(filePath, 'utf-8'); content = fs.readFileSync(decodedFilePath, 'utf-8');
} else { } else {
const buffer = fs.readFileSync(filePath); const buffer = fs.readFileSync(decodedFilePath);
const iconv = require('iconv-lite'); const iconv = require('iconv-lite');
content = iconv.decode(buffer, fallbackEncoding); content = iconv.decode(buffer, fallbackEncoding);
} }
@ -74,13 +77,13 @@ export async function GET(request: Request) {
// If no encoding worked, try reading as buffer and return as base64 // If no encoding worked, try reading as buffer and return as base64
if (!content || content.length === 0) { if (!content || content.length === 0) {
try { try {
const buffer = fs.readFileSync(filePath); const buffer = fs.readFileSync(decodedFilePath);
content = buffer.toString('base64'); content = buffer.toString('base64');
return NextResponse.json({ return NextResponse.json({
content, content,
size: stats.size, size: stats.size,
path: filePath, path: decodedFilePath,
name: path.basename(filePath), name: path.basename(decodedFilePath),
encoding: 'base64' encoding: 'base64'
}); });
} catch (err) { } catch (err) {
@ -91,8 +94,8 @@ export async function GET(request: Request) {
return NextResponse.json({ return NextResponse.json({
content, content,
size: stats.size, size: stats.size,
path: filePath, path: decodedFilePath,
name: path.basename(filePath), name: path.basename(decodedFilePath),
encoding: encoding encoding: encoding
}); });
} catch (error: any) { } catch (error: any) {

View File

@ -16,19 +16,22 @@ export async function GET(request: Request) {
return NextResponse.json({ error: "Path is required" }, { status: 400 }); return NextResponse.json({ error: "Path is required" }, { status: 400 });
} }
// Decode the URL-encoded path to handle special characters like +, spaces, Chinese characters, etc.
const decodedPath = decodeURIComponent(dirPath);
try { try {
const db = getDatabase(); const db = getDatabase();
const files = fs.readdirSync(dirPath); const files = fs.readdirSync(decodedPath);
// Get media files from database for this path // Get media files from database for this path
const mediaFiles = db.prepare(` const mediaFiles = db.prepare(`
SELECT id, path, type, thumbnail, avg_rating, star_count SELECT id, path, type, thumbnail, avg_rating, star_count
FROM media FROM media
WHERE path LIKE ? WHERE path LIKE ?
`).all(`${dirPath}%`) as Array<{id: number, path: string, type: string, thumbnail: string | null, avg_rating: number, star_count: number}>; `).all(`${decodedPath}%`) as Array<{id: number, path: string, type: string, thumbnail: string | null, avg_rating: number, star_count: number}>;
const result = files.map((file) => { const result = files.map((file) => {
const filePath = path.join(dirPath, file); const filePath = path.join(decodedPath, file);
const stats = fs.statSync(filePath); const stats = fs.statSync(filePath);
const ext = path.extname(file).toLowerCase(); const ext = path.extname(file).toLowerCase();