@@ -64,7 +64,9 @@ export async function getPages(lang: string = 'de') {
|
||||
|
||||
const directories = items.filter(
|
||||
(item: any) =>
|
||||
item.type === "directory" && !item.basename.startsWith("."),
|
||||
item.type === "directory" &&
|
||||
!item.basename.startsWith(".") &&
|
||||
!item.basename.startsWith("_"),
|
||||
);
|
||||
|
||||
const pages = await Promise.all(
|
||||
|
||||
@@ -6,44 +6,64 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
const { slug, lang } = params;
|
||||
const language = lang || 'de';
|
||||
|
||||
// Capitalize the first letter to match the convention: fotos -> Fotos.md
|
||||
const baseName = slug.charAt(0).toUpperCase() + slug.slice(1);
|
||||
const filename = language === 'de' ? `${baseName}.md` : `${baseName}.${language}.md`;
|
||||
const path = `/${slug}/${filename}`;
|
||||
// Try both the regular slug and the hidden (_slug) folder
|
||||
const slugsToTry = [slug, `_${slug}`];
|
||||
let rawContent = "";
|
||||
let finalSlug = slug;
|
||||
let baseName = "";
|
||||
let filename = "";
|
||||
|
||||
for (const s of slugsToTry) {
|
||||
const cleanSlug = s.startsWith('_') ? s.slice(1) : s;
|
||||
baseName = cleanSlug.charAt(0).toUpperCase() + cleanSlug.slice(1);
|
||||
|
||||
filename = language === 'de' ? `${baseName}.md` : `${baseName}.${language}.md`;
|
||||
const path = `/${s}/${filename}`;
|
||||
|
||||
try {
|
||||
let rawContent;
|
||||
try {
|
||||
rawContent = await getPageContent(path);
|
||||
try {
|
||||
rawContent = await getPageContent(path);
|
||||
finalSlug = s;
|
||||
break; // Found it!
|
||||
} catch (e) {
|
||||
if (language !== 'de') {
|
||||
console.warn(`Localized content ${filename} not found in ${s}, falling back to German.`);
|
||||
rawContent = await getPageContent(`/${s}/${baseName}.md`);
|
||||
finalSlug = s;
|
||||
break; // Found fallback
|
||||
} else {
|
||||
throw e; // Try next slug variant
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (language !== 'de') {
|
||||
console.warn(`Localized content ${filename} not found, falling back to German.`);
|
||||
rawContent = await getPageContent(`/${slug}/${baseName}.md`);
|
||||
} else {
|
||||
throw e;
|
||||
if (s === slugsToTry[slugsToTry.length - 1]) {
|
||||
console.error(`Error fetching page from Nextcloud for slug ${slug}`, e);
|
||||
throw error(404, "Page not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Extract the first header (e.g., # Title or ## Title)
|
||||
const headerMatch = rawContent.match(/^#{1,6}\s+(.+)$/m);
|
||||
const title = headerMatch ? headerMatch[1] : baseName;
|
||||
const title = headerMatch ? headerMatch[1] : (finalSlug.startsWith('_') ? finalSlug.slice(1) : finalSlug);
|
||||
|
||||
// Remove the first header from content so it's not rendered twice
|
||||
const content = headerMatch
|
||||
? rawContent.replace(headerMatch[0], "").trim()
|
||||
: rawContent;
|
||||
|
||||
const coverImage = await getCoverImage(slug);
|
||||
const coverImage = await getCoverImage(finalSlug);
|
||||
|
||||
return {
|
||||
content,
|
||||
title,
|
||||
slug,
|
||||
slug: finalSlug,
|
||||
coverImage,
|
||||
lang: language
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(`Error fetching ${filename} from Nextcloud`, e);
|
||||
console.error(`Error processing content for ${finalSlug}`, e);
|
||||
throw error(404, "Page not found");
|
||||
}
|
||||
};
|
||||
@@ -17,67 +17,83 @@ export const GET: RequestHandler = async ({ params, url }) => {
|
||||
let buffer: ArrayBuffer;
|
||||
let contentType: string;
|
||||
|
||||
if (width || height) {
|
||||
// Use Nextcloud Preview API
|
||||
const baseUrl = env.NEXTCLOUD_URL?.endsWith("/") ? env.NEXTCLOUD_URL : `${env.NEXTCLOUD_URL}/`;
|
||||
|
||||
let fullPath = path;
|
||||
if (env.NEXTCLOUD_BASE_DIR) {
|
||||
const baseDir = env.NEXTCLOUD_BASE_DIR.replace(/^\/+|\/+$/g, "");
|
||||
fullPath = baseDir ? `${baseDir}/${path}` : path;
|
||||
}
|
||||
|
||||
const previewUrl = new URL(`${baseUrl}index.php/core/preview`);
|
||||
// Ensure leading slash for the file parameter
|
||||
const fileParam = fullPath.startsWith('/') ? fullPath : `/${fullPath}`;
|
||||
previewUrl.searchParams.set("file", fileParam);
|
||||
if (width) previewUrl.searchParams.set("x", width);
|
||||
if (height) previewUrl.searchParams.set("y", height);
|
||||
previewUrl.searchParams.set("forceIcon", "0");
|
||||
|
||||
const auth = Buffer.from(`${env.NEXTCLOUD_USER}:${env.NEXTCLOUD_PASSWORD}`).toString("base64");
|
||||
|
||||
console.log(`Fetching preview: ${previewUrl.toString()} for file: ${fullPath}`);
|
||||
|
||||
try {
|
||||
const response = await fetch(previewUrl.toString(), {
|
||||
headers: {
|
||||
"Authorization": `Basic ${auth}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
buffer = await response.arrayBuffer();
|
||||
contentType = response.headers.get("Content-Type") || "image/png";
|
||||
|
||||
return new Response(buffer, {
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
"Cache-Control": "public, max-age=86400",
|
||||
"Vary": "Accept-Encoding"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn(`Nextcloud preview failed (${response.status} ${response.statusText}) for ${fullPath}. Falling back to original.`);
|
||||
}
|
||||
} catch (fetchError) {
|
||||
console.error(`Fetch error during preview request for ${fullPath}:`, fetchError);
|
||||
}
|
||||
// Try both original path and hidden variant if applicable
|
||||
const pathsToTry = [path];
|
||||
if (!path.startsWith('_')) {
|
||||
pathsToTry.push(`_${path}`);
|
||||
}
|
||||
|
||||
// Fetch original via WebDAV (Fallback or no resize requested)
|
||||
console.log(`Fetching original file via WebDAV: /${path}`);
|
||||
const data = await client.getFileContents("/" + path);
|
||||
buffer = data as ArrayBuffer;
|
||||
contentType = mime.lookup(path) || "application/octet-stream";
|
||||
|
||||
return new Response(buffer, {
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
"Cache-Control": "public, max-age=86400",
|
||||
"Vary": "Accept-Encoding"
|
||||
let response: Response | null = null;
|
||||
let lastError: any = null;
|
||||
|
||||
for (const currentPath of pathsToTry) {
|
||||
try {
|
||||
if (width || height) {
|
||||
// Use Nextcloud Preview API
|
||||
const baseUrl = env.NEXTCLOUD_URL?.endsWith("/") ? env.NEXTCLOUD_URL : `${env.NEXTCLOUD_URL}/`;
|
||||
|
||||
let fullPath = currentPath;
|
||||
if (env.NEXTCLOUD_BASE_DIR) {
|
||||
const baseDir = env.NEXTCLOUD_BASE_DIR.replace(/^\/+|\/+$/g, "");
|
||||
fullPath = baseDir ? `${baseDir}/${currentPath}` : currentPath;
|
||||
}
|
||||
|
||||
const isJpg = fullPath.match(/\.(jpg|jpeg)$/i);
|
||||
const previewExtension = isJpg ? 'jpg' : 'png';
|
||||
const previewUrl = new URL(`${baseUrl}index.php/core/preview.${previewExtension}`);
|
||||
// Ensure leading slash for the file parameter
|
||||
const fileParam = fullPath.startsWith('/') ? fullPath : `/${fullPath}`;
|
||||
previewUrl.searchParams.set("file", fileParam);
|
||||
if (width) previewUrl.searchParams.set("x", width);
|
||||
if (height) previewUrl.searchParams.set("y", height);
|
||||
previewUrl.searchParams.set("forceIcon", "0");
|
||||
|
||||
const auth = Buffer.from(`${env.NEXTCLOUD_USER}:${env.NEXTCLOUD_PASSWORD}`).toString("base64");
|
||||
|
||||
console.log(`Fetching preview: ${previewUrl.toString()} for file: ${fullPath}`);
|
||||
|
||||
const ncResponse = await fetch(previewUrl.toString(), {
|
||||
headers: {
|
||||
"Authorization": `Basic ${auth}`
|
||||
}
|
||||
});
|
||||
|
||||
if (ncResponse.ok) {
|
||||
buffer = await ncResponse.arrayBuffer();
|
||||
contentType = ncResponse.headers.get("Content-Type") || "image/png";
|
||||
|
||||
return new Response(buffer, {
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
"Cache-Control": "public, max-age=86400",
|
||||
"Vary": "Accept-Encoding"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn(`Nextcloud preview failed (${ncResponse.status}) for ${fullPath}.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch original via WebDAV (Fallback or no resize requested)
|
||||
console.log(`Fetching original file via WebDAV: /${currentPath}`);
|
||||
const data = await client.getFileContents("/" + currentPath);
|
||||
buffer = data as ArrayBuffer;
|
||||
contentType = mime.lookup(currentPath) || "application/octet-stream";
|
||||
|
||||
return new Response(buffer, {
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
"Cache-Control": "public, max-age=86400",
|
||||
"Vary": "Accept-Encoding"
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
lastError = e;
|
||||
continue; // Try next path variant
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
throw lastError || new Error("Asset not found");
|
||||
} catch (e) {
|
||||
console.error(`Error fetching asset from Nextcloud: ${path}`, e);
|
||||
throw error(404, "Asset not found");
|
||||
|
||||
Reference in New Issue
Block a user