mirror of
https://github.com/VERT-sh/VERT.git
synced 2026-05-24 09:29:11 -05:00
feat: vertd custom headers (#180)
allows for adding custom headers to vertd requests. fixes #180
This commit is contained in:
@@ -289,6 +289,11 @@
|
||||
"us": "Washington, USA",
|
||||
"custom": "Custom"
|
||||
},
|
||||
"custom_headers": {
|
||||
"label": "Custom headers",
|
||||
"description": "Add custom headers to be sent with each request to the vertd instance, which could be used for authentication or other purposes (one per line).",
|
||||
"placeholder": "Header-Name: Header Value"
|
||||
},
|
||||
"conversion_speed": {
|
||||
"label": "Conversion speed",
|
||||
"description": "This describes the tradeoff between speed and quality. Faster speeds will result in lower quality, but will get the job done quicker.",
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLInputAttributes } from "svelte/elements";
|
||||
|
||||
interface Props extends HTMLInputAttributes {
|
||||
interface Props extends Omit<
|
||||
HTMLInputAttributes,
|
||||
keyof HTMLInputAttributes
|
||||
> {
|
||||
extension?: string;
|
||||
prefix?: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -14,6 +19,7 @@
|
||||
disabled = false,
|
||||
extension,
|
||||
prefix,
|
||||
multiline = false,
|
||||
...rest
|
||||
}: Props = $props();
|
||||
</script>
|
||||
@@ -22,32 +28,52 @@
|
||||
{#if type === "checkbox"}
|
||||
<div class="relative w-full h-full">
|
||||
<input
|
||||
{...rest}
|
||||
type="checkbox"
|
||||
bind:checked
|
||||
{disabled}
|
||||
class="w-full p-3 rounded-lg bg-panel border-2 border-button
|
||||
{...rest}
|
||||
type="checkbox"
|
||||
bind:checked
|
||||
{disabled}
|
||||
class="w-full p-3 rounded-lg bg-panel border-2 border-button
|
||||
{prefix ? 'pl-[2rem]' : 'pl-3'}
|
||||
{extension ? 'pr-[4rem]' : 'pr-3'}
|
||||
{disabled && 'opacity-50 cursor-not-allowed'} appearance-none"
|
||||
/>
|
||||
{#if checked}
|
||||
<div class="absolute w-7 h-7 inset-0 flex items-center justify-center pointer-events-none">
|
||||
<svg class="w-6 h-6" fill="var(--bg-panel)" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
||||
<div
|
||||
class="absolute w-7 h-7 inset-0 flex items-center justify-center pointer-events-none"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6"
|
||||
fill="var(--bg-panel)"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if multiline}
|
||||
<textarea
|
||||
{...rest}
|
||||
bind:value
|
||||
{disabled}
|
||||
class="w-full p-3 rounded-lg bg-panel border-2 border-button
|
||||
{prefix ? 'pl-[2rem]' : 'pl-3'}
|
||||
{extension ? 'pr-[4rem]' : 'pr-3'}
|
||||
{disabled && 'opacity-50 cursor-not-allowed'}"
|
||||
></textarea>
|
||||
{:else}
|
||||
<input
|
||||
{...rest}
|
||||
bind:value
|
||||
{disabled}
|
||||
class="w-full p-3 rounded-lg bg-panel border-2 border-button
|
||||
{prefix ? 'pl-[2rem]' : 'pl-3'}
|
||||
{extension ? 'pr-[4rem]' : 'pr-3'}
|
||||
{disabled && 'opacity-50 cursor-not-allowed'}"
|
||||
{prefix ? 'pl-[2rem]' : 'pl-3'}
|
||||
{extension ? 'pr-[4rem]' : 'pr-3'}
|
||||
{disabled && 'opacity-50 cursor-not-allowed'}"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
placeholder={setting.placeholder}
|
||||
disabled={disabled ||
|
||||
setting.disabled}
|
||||
oninput={(e) =>
|
||||
oninput={(e: any) =>
|
||||
handleSettingChange(
|
||||
setting.customInputKey!,
|
||||
e.currentTarget
|
||||
@@ -238,7 +238,7 @@
|
||||
] ??
|
||||
setting.default}
|
||||
placeholder={setting.placeholder}
|
||||
onchange={(e) =>
|
||||
onchange={(e: any) =>
|
||||
handleSettingChange(
|
||||
setting.key,
|
||||
e.currentTarget.checked,
|
||||
@@ -295,7 +295,7 @@
|
||||
] ??
|
||||
setting.default}
|
||||
placeholder={setting.placeholder}
|
||||
oninput={(e) =>
|
||||
oninput={(e: any) =>
|
||||
handleSettingChange(
|
||||
setting.key,
|
||||
e.currentTarget.value,
|
||||
|
||||
@@ -2,7 +2,10 @@ import VertdErrorComponent from "$lib/components/functional/popups/VertdError.sv
|
||||
import { error, log } from "$lib/util/logger";
|
||||
import { m } from "$lib/paraglide/messages";
|
||||
import { Settings } from "$lib/sections/settings/index.svelte";
|
||||
import { VertdInstance } from "$lib/sections/settings/vertdSettings.svelte";
|
||||
import {
|
||||
VertdInstance,
|
||||
getVertdCustomHeaders,
|
||||
} from "$lib/sections/settings/vertdSettings.svelte";
|
||||
import { VertFile } from "$lib/types";
|
||||
import { Converter, FormatInfo } from "./converter.svelte";
|
||||
import { PUB_DISABLE_FAILURE_BLOCKS } from "$env/static/public";
|
||||
@@ -60,16 +63,18 @@ export const vertdFetch: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} = async (url: any, options: RequestInit, body?: any) => {
|
||||
const domain = await VertdInstance.instance.url();
|
||||
const headers = new Headers(options.headers);
|
||||
for (const [key, value] of Object.entries(getVertdCustomHeaders()))
|
||||
headers.set(key, value);
|
||||
|
||||
// if there is a body, insert a Content-Type: application/json header
|
||||
if (body) {
|
||||
options.headers = {
|
||||
"Content-Type": "application/json",
|
||||
...(options.headers || {}),
|
||||
};
|
||||
headers.set("Content-Type", "application/json");
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
options.headers = headers;
|
||||
|
||||
const res = await fetch(domain + url, options);
|
||||
|
||||
const text = await res.text();
|
||||
@@ -250,6 +255,7 @@ const createUploadTask = async (file: VertFile): Promise<UploadTask> => {
|
||||
formData.append("file", file.file, file.name);
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", `${apiUrl}/api/upload`, true);
|
||||
const customHeaders = getVertdCustomHeaders();
|
||||
|
||||
const promise = new Promise<UploadResponse>((resolve, reject) => {
|
||||
xhr.upload.addEventListener("progress", (e) => {
|
||||
@@ -285,6 +291,9 @@ const createUploadTask = async (file: VertFile): Promise<UploadTask> => {
|
||||
reject(new Error("Conversion cancelled"));
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(customHeaders))
|
||||
xhr.setRequestHeader(key, value);
|
||||
|
||||
xhr.send(formData);
|
||||
console.log("sent!");
|
||||
});
|
||||
@@ -299,6 +308,7 @@ const downloadFile = async (url: string, file: VertFile): Promise<Blob> => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, true);
|
||||
xhr.responseType = "blob";
|
||||
const customHeaders = getVertdCustomHeaders();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
xhr.addEventListener("progress", (e) => {
|
||||
@@ -322,6 +332,9 @@ const downloadFile = async (url: string, file: VertFile): Promise<Blob> => {
|
||||
reject(xhr.statusText);
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(customHeaders))
|
||||
xhr.setRequestHeader(key, value);
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
};
|
||||
@@ -712,7 +725,7 @@ export class VertdConverter extends Converter {
|
||||
// trim/crop/rotate - also have another ui for this prob
|
||||
|
||||
const animatedImages = [".gif", ".webp", ".apng"];
|
||||
if (animatedImages.includes(input.from)) {
|
||||
if (animatedImages.includes(input.to)) {
|
||||
return [fps, resolution, metadata];
|
||||
} else {
|
||||
return [
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
import { vertdLoaded } from "$lib/store/index.svelte";
|
||||
import { m } from "$lib/paraglide/messages";
|
||||
import { link, sanitize } from "$lib/store/index.svelte";
|
||||
import { VertdInstance, type VertdInner } from "./vertdSettings.svelte";
|
||||
import {
|
||||
VertdInstance,
|
||||
getVertdCustomHeaders,
|
||||
type VertdInner,
|
||||
} from "./vertdSettings.svelte";
|
||||
import FancyInput from "$lib/components/functional/FancyInput.svelte";
|
||||
|
||||
let vertdCommit = $state<string | null>(null);
|
||||
@@ -24,7 +28,12 @@
|
||||
vertdCommit = "loading";
|
||||
VertdInstance.instance
|
||||
.url()
|
||||
.then((u) => fetch(`${u}/api/version`, { signal }))
|
||||
.then((u) =>
|
||||
fetch(`${u}/api/version`, {
|
||||
signal,
|
||||
headers: getVertdCustomHeaders(),
|
||||
}),
|
||||
)
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error("bad response");
|
||||
vertdLoaded.set(false);
|
||||
@@ -57,32 +66,41 @@
|
||||
/>
|
||||
{m["settings.vertd.title"]()}
|
||||
</h2>
|
||||
<p
|
||||
class={clsx("text-sm font-normal", {
|
||||
"text-failure": vertdCommit === null,
|
||||
"text-green-700 dynadark:text-green-300": vertdCommit !== null,
|
||||
"!text-muted": vertdCommit === "loading",
|
||||
})}
|
||||
>
|
||||
{m["settings.vertd.status"]()}
|
||||
{vertdCommit
|
||||
? vertdCommit === "loading"
|
||||
? m["settings.vertd.loading"]()
|
||||
: m["settings.vertd.available"]({ commitId: vertdCommit })
|
||||
: m["settings.vertd.unavailable"]()}
|
||||
</p>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{@html sanitize(m["settings.vertd.description.main"]())}
|
||||
</p>
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{@html sanitize(link(
|
||||
<div class="flex flex-col gap-4">
|
||||
<p
|
||||
class={clsx("text-sm font-normal", {
|
||||
"text-failure": vertdCommit === null,
|
||||
"text-green-700 dynadark:text-green-300":
|
||||
vertdCommit !== null,
|
||||
"!text-muted": vertdCommit === "loading",
|
||||
})}
|
||||
>
|
||||
{m["settings.vertd.status"]()}
|
||||
{vertdCommit
|
||||
? vertdCommit === "loading"
|
||||
? m["settings.vertd.loading"]()
|
||||
: m["settings.vertd.available"]({
|
||||
commitId: vertdCommit,
|
||||
})
|
||||
: m["settings.vertd.unavailable"]()}
|
||||
</p>
|
||||
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{@html sanitize(m["settings.vertd.description.main"]())}
|
||||
</p>
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{@html sanitize(
|
||||
link(
|
||||
"vertd_link",
|
||||
m["settings.vertd.description.info"](),
|
||||
GITHUB_URL_VERTD,
|
||||
))}
|
||||
</p>
|
||||
),
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base font-bold">
|
||||
{m["settings.vertd.instance.label"]()}
|
||||
@@ -135,75 +153,117 @@
|
||||
{#if VertdInstance.instance.innerData().type === "custom"}
|
||||
<FancyInput
|
||||
type="text"
|
||||
placeholder={m["settings.vertd.instance.url_placeholder"]()}
|
||||
placeholder={m[
|
||||
"settings.vertd.instance.url_placeholder"
|
||||
]()}
|
||||
bind:value={settings.vertdURL}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base font-bold">
|
||||
{m["settings.vertd.conversion_speed.label"]()}
|
||||
</p>
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{m["settings.vertd.conversion_speed.description"]()}
|
||||
</p>
|
||||
</div>
|
||||
<Dropdown
|
||||
options={[
|
||||
m["settings.vertd.conversion_speed.speeds.very_slow"](),
|
||||
m["settings.vertd.conversion_speed.speeds.slower"](),
|
||||
m["settings.vertd.conversion_speed.speeds.slow"](),
|
||||
m["settings.vertd.conversion_speed.speeds.medium"](),
|
||||
m["settings.vertd.conversion_speed.speeds.fast"](),
|
||||
m["settings.vertd.conversion_speed.speeds.ultra_fast"](),
|
||||
]}
|
||||
settingsStyle
|
||||
selected={(() => {
|
||||
switch (settings.vertdSpeed) {
|
||||
case "verySlow":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.very_slow"
|
||||
]();
|
||||
case "slower":
|
||||
return m["settings.vertd.conversion_speed.speeds.slower"]();
|
||||
case "slow":
|
||||
return m["settings.vertd.conversion_speed.speeds.slow"]();
|
||||
case "medium":
|
||||
return m["settings.vertd.conversion_speed.speeds.medium"]();
|
||||
case "fast":
|
||||
return m["settings.vertd.conversion_speed.speeds.fast"]();
|
||||
case "ultraFast":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.ultra_fast"
|
||||
]();
|
||||
}
|
||||
})()}
|
||||
onselect={(selected) => {
|
||||
switch (selected) {
|
||||
case m["settings.vertd.conversion_speed.speeds.very_slow"]():
|
||||
settings.vertdSpeed = "verySlow";
|
||||
break;
|
||||
case m["settings.vertd.conversion_speed.speeds.slower"]():
|
||||
settings.vertdSpeed = "slower";
|
||||
break;
|
||||
case m["settings.vertd.conversion_speed.speeds.slow"]():
|
||||
settings.vertdSpeed = "slow";
|
||||
break;
|
||||
case m["settings.vertd.conversion_speed.speeds.medium"]():
|
||||
settings.vertdSpeed = "medium";
|
||||
break;
|
||||
case m["settings.vertd.conversion_speed.speeds.fast"]():
|
||||
settings.vertdSpeed = "fast";
|
||||
break;
|
||||
case m["settings.vertd.conversion_speed.speeds.ultra_fast"]():
|
||||
settings.vertdSpeed = "ultraFast";
|
||||
break;
|
||||
}
|
||||
}}
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base font-bold">
|
||||
{m["settings.vertd.conversion_speed.label"]()}
|
||||
</p>
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{m["settings.vertd.conversion_speed.description"]()}
|
||||
</p>
|
||||
</div>
|
||||
<Dropdown
|
||||
options={[
|
||||
m["settings.vertd.conversion_speed.speeds.very_slow"](),
|
||||
m["settings.vertd.conversion_speed.speeds.slower"](),
|
||||
m["settings.vertd.conversion_speed.speeds.slow"](),
|
||||
m["settings.vertd.conversion_speed.speeds.medium"](),
|
||||
m["settings.vertd.conversion_speed.speeds.fast"](),
|
||||
m[
|
||||
"settings.vertd.conversion_speed.speeds.ultra_fast"
|
||||
](),
|
||||
]}
|
||||
settingsStyle
|
||||
selected={(() => {
|
||||
switch (settings.vertdSpeed) {
|
||||
case "verySlow":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.very_slow"
|
||||
]();
|
||||
case "slower":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.slower"
|
||||
]();
|
||||
case "slow":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.slow"
|
||||
]();
|
||||
case "medium":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.medium"
|
||||
]();
|
||||
case "fast":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.fast"
|
||||
]();
|
||||
case "ultraFast":
|
||||
return m[
|
||||
"settings.vertd.conversion_speed.speeds.ultra_fast"
|
||||
]();
|
||||
}
|
||||
})()}
|
||||
onselect={(selected) => {
|
||||
switch (selected) {
|
||||
case m[
|
||||
"settings.vertd.conversion_speed.speeds.very_slow"
|
||||
]():
|
||||
settings.vertdSpeed = "verySlow";
|
||||
break;
|
||||
case m[
|
||||
"settings.vertd.conversion_speed.speeds.slower"
|
||||
]():
|
||||
settings.vertdSpeed = "slower";
|
||||
break;
|
||||
case m[
|
||||
"settings.vertd.conversion_speed.speeds.slow"
|
||||
]():
|
||||
settings.vertdSpeed = "slow";
|
||||
break;
|
||||
case m[
|
||||
"settings.vertd.conversion_speed.speeds.medium"
|
||||
]():
|
||||
settings.vertdSpeed = "medium";
|
||||
break;
|
||||
case m[
|
||||
"settings.vertd.conversion_speed.speeds.fast"
|
||||
]():
|
||||
settings.vertdSpeed = "fast";
|
||||
break;
|
||||
case m[
|
||||
"settings.vertd.conversion_speed.speeds.ultra_fast"
|
||||
]():
|
||||
settings.vertdSpeed = "ultraFast";
|
||||
break;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base font-bold">
|
||||
{m["settings.vertd.custom_headers.label"]()}
|
||||
</p>
|
||||
<p class="text-sm text-muted font-normal">
|
||||
{m["settings.vertd.custom_headers.description"]()}
|
||||
</p>
|
||||
<FancyInput
|
||||
type="text"
|
||||
bind:value={settings.vertdCustomHeaders}
|
||||
placeholder={m[
|
||||
"settings.vertd.custom_headers.placeholder"
|
||||
]()}
|
||||
multiline
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
</div></Panel
|
||||
>
|
||||
|
||||
@@ -25,11 +25,12 @@ export interface ISettings {
|
||||
plausible: boolean;
|
||||
vertdURL: string;
|
||||
vertdSpeed: ConversionSpeed; // videos
|
||||
vertdBlockedHashes: Map<string, Date[]>; // hashes of files blocked from vertd conversion
|
||||
vertdCustomHeaders: string; // custom headers to send to the vertd server
|
||||
magickQuality: number; // images
|
||||
ffmpegQuality: ConversionBitrate; // audio (or audio <-> video)
|
||||
ffmpegSampleRate: string; // audio (or audio <-> video)
|
||||
ffmpegCustomSampleRate: number; // audio (or audio <-> video) - only used when ffmpegSampleRate is "custom"
|
||||
vertdBlockedHashes: Map<string, Date[]>; // hashes of files blocked from vertd conversion
|
||||
}
|
||||
|
||||
export class Settings {
|
||||
@@ -48,11 +49,12 @@ export class Settings {
|
||||
plausible: true,
|
||||
vertdURL: PUB_VERTD_URL,
|
||||
vertdSpeed: "slow",
|
||||
vertdBlockedHashes: new Map<string, Date[]>(),
|
||||
vertdCustomHeaders: "",
|
||||
magickQuality: 100,
|
||||
ffmpegQuality: "auto",
|
||||
ffmpegSampleRate: "auto",
|
||||
ffmpegCustomSampleRate: 44100, //TODO: make string to match for vertd
|
||||
vertdBlockedHashes: new Map<string, Date[]>(),
|
||||
});
|
||||
|
||||
public save() {
|
||||
|
||||
@@ -13,6 +13,29 @@ export type VertdInner =
|
||||
| { type: "us" }
|
||||
| { type: "custom" };
|
||||
|
||||
export const getVertdCustomHeaders = (): Record<string, string> => {
|
||||
const raw = Settings.instance.settings.vertdCustomHeaders.trim();
|
||||
if (!raw) return {};
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
for (const line of raw.split(/\r?\n/)) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
|
||||
const separatorIndex = trimmed.indexOf(":");
|
||||
if (separatorIndex <= 0) continue;
|
||||
|
||||
const key = trimmed.slice(0, separatorIndex).trim();
|
||||
const value = trimmed.slice(separatorIndex + 1).trim();
|
||||
if (!key || !value) continue;
|
||||
|
||||
headers[key] = value;
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
export class VertdInstance {
|
||||
public static instance = new VertdInstance();
|
||||
|
||||
@@ -61,7 +84,8 @@ export class VertdInstance {
|
||||
await fetch(url, {
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
mode: "no-cors",
|
||||
mode: "cors",
|
||||
headers: getVertdCustomHeaders(),
|
||||
});
|
||||
return performance.now() - start;
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user