mirror of https://github.com/VERT-sh/VERT.git
feat: statically generate conversion slugs
needs refinement cause building takes forever
This commit is contained in:
parent
d89a343eed
commit
95284a84d4
|
|
@ -46,8 +46,8 @@
|
||||||
const color = $derived(
|
const color = $derived(
|
||||||
Object.values(colors).find((p) => p.matcher(page.url.pathname)) || {
|
Object.values(colors).find((p) => p.matcher(page.url.pathname)) || {
|
||||||
matcher: () => false,
|
matcher: () => false,
|
||||||
color: "transparent",
|
color: "var(--bg-gradient-from)",
|
||||||
at: 0,
|
at: 100,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -64,9 +64,14 @@
|
||||||
const maskImage = $derived(
|
const maskImage = $derived(
|
||||||
`linear-gradient(to top, transparent ${100 - at.current}%, black 100%)`,
|
`linear-gradient(to top, transparent ${100 - at.current}%, black 100%)`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const showLogo = $derived(
|
||||||
|
page.url.pathname === "/" ||
|
||||||
|
/^[\w-]+-[\w-]+$/.test(page.url.pathname.replace(/^\/|\/$/g, "")),
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if page.url.pathname === "/"}
|
{#if showLogo}
|
||||||
<div
|
<div
|
||||||
class="fixed -z-30 top-0 left-0 w-screen h-screen flex items-center justify-center overflow-hidden"
|
class="fixed -z-30 top-0 left-0 w-screen h-screen flex items-center justify-center overflow-hidden"
|
||||||
transition:fade={{
|
transition:fade={{
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,9 @@
|
||||||
{
|
{
|
||||||
name: m["navbar.upload"](),
|
name: m["navbar.upload"](),
|
||||||
url: "/",
|
url: "/",
|
||||||
activeMatch: (pathname) => pathname === "/",
|
activeMatch: (pathname) =>
|
||||||
|
pathname === "/" ||
|
||||||
|
/^[\w-]+-[\w-]+$/.test(pathname.replace(/^\/|\/$/g, "")),
|
||||||
icon: UploadIcon,
|
icon: UploadIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
import { converters } from "$lib/converters";
|
||||||
|
import type { EntryGenerator } from "./$types";
|
||||||
|
|
||||||
|
// generate conversion pairs at build time (e.g. mkv-mp4) for SEO
|
||||||
|
export const entries: EntryGenerator = () => {
|
||||||
|
const seenPairs = new Set<string>();
|
||||||
|
|
||||||
|
const addPair = (
|
||||||
|
fromName: string,
|
||||||
|
fromSupported: boolean,
|
||||||
|
toName: string,
|
||||||
|
toSupported: boolean,
|
||||||
|
) => {
|
||||||
|
if (!fromSupported || !toSupported || fromName === toName) return;
|
||||||
|
|
||||||
|
const from = fromName.replace(".", "").toLowerCase();
|
||||||
|
const to = toName.replace(".", "").toLowerCase();
|
||||||
|
const slug = `${from}-${to}`;
|
||||||
|
|
||||||
|
if (!seenPairs.has(slug)) seenPairs.add(slug);
|
||||||
|
};
|
||||||
|
|
||||||
|
// check all conversions (same converter and cross-converter)
|
||||||
|
for (const fromConverter of converters) {
|
||||||
|
for (const toConverter of converters) {
|
||||||
|
const sameConverter = fromConverter.name === toConverter.name;
|
||||||
|
|
||||||
|
for (const fromFormat of fromConverter.supportedFormats) {
|
||||||
|
for (const toFormat of toConverter.supportedFormats) {
|
||||||
|
// skip if same converter and same format, or if different converter but formats are the same
|
||||||
|
if (sameConverter && fromFormat.name === toFormat.name)
|
||||||
|
continue;
|
||||||
|
if (!sameConverter && fromFormat.name === toFormat.name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addPair(
|
||||||
|
fromFormat.name,
|
||||||
|
fromFormat.fromSupported,
|
||||||
|
toFormat.name,
|
||||||
|
toFormat.toSupported,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = Array.from(seenPairs).map((slug) => ({ formats: slug }));
|
||||||
|
console.log(`[SEO] generating ${result.length} format conversion routes`);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const prerender = true;
|
||||||
|
|
||||||
|
export const load = ({ params }) => {
|
||||||
|
const { formats } = params;
|
||||||
|
|
||||||
|
// parse the slug (e.g. { from: "mkv", to: "mp4" })
|
||||||
|
const parts = formats.split("-");
|
||||||
|
|
||||||
|
if (parts.length !== 2) {
|
||||||
|
return {
|
||||||
|
fromFormat: null,
|
||||||
|
toFormat: null,
|
||||||
|
error: "Invalid format slug",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [from, to] = parts;
|
||||||
|
const fromFormat = `.${from}`;
|
||||||
|
const toFormat = `.${to}`;
|
||||||
|
|
||||||
|
let fromValid = false;
|
||||||
|
let toValid = false;
|
||||||
|
|
||||||
|
for (const converter of converters) {
|
||||||
|
for (const format of converter.supportedFormats) {
|
||||||
|
if (format.name === fromFormat && format.fromSupported)
|
||||||
|
fromValid = true;
|
||||||
|
if (format.name === toFormat && format.toSupported) toValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fromValid || !toValid) {
|
||||||
|
return {
|
||||||
|
fromFormat: null,
|
||||||
|
toFormat: null,
|
||||||
|
error: "Invalid conversion pair",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
fromFormat,
|
||||||
|
toFormat,
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { error, log } from "$lib/logger";
|
||||||
|
import Index from "../+page.svelte";
|
||||||
|
const { data } = $props();
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (data.fromFormat && data.toFormat) {
|
||||||
|
log(["SEO"], `converting from: ${data.fromFormat}`);
|
||||||
|
log(["SEO"], `converting to: ${data.toFormat}`);
|
||||||
|
} else if (data.error) {
|
||||||
|
error(["SEO"], `invalid slug: ${data.error}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
{#if data.fromFormat && data.toFormat}
|
||||||
|
<title
|
||||||
|
>Convert {data.fromFormat.replace(".", "").toUpperCase()} to {data.toFormat
|
||||||
|
.replace(".", "")
|
||||||
|
.toUpperCase()} - VERT</title
|
||||||
|
>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Convert {data.fromFormat
|
||||||
|
.replace('.', '')
|
||||||
|
.toUpperCase()} files to {data.toFormat
|
||||||
|
.replace('.', '')
|
||||||
|
.toUpperCase()} with VERT. No ads, no tracking, open source, and all processing (other than video) is done on your device."
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<!-- render main upload page -->
|
||||||
|
<Index />
|
||||||
Loading…
Reference in New Issue