mirror of https://github.com/VERT-sh/VERT.git
feat: vertd
This commit is contained in:
parent
35e98a5971
commit
8353491f64
16
src/app.scss
16
src/app.scss
|
|
@ -259,4 +259,20 @@ body {
|
|||
h6 {
|
||||
@apply font-display font-semibold;
|
||||
}
|
||||
|
||||
code {
|
||||
@apply font-mono bg-gray-200 rounded-md px-1 dynadark:bg-panel-alt dynadark:text-white;
|
||||
}
|
||||
|
||||
p a {
|
||||
@apply text-accent underline;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
@apply w-full p-3 rounded-lg bg-panel border-2 border-button pl-3 pr-[4rem];
|
||||
}
|
||||
|
||||
input[type="text"]::placeholder {
|
||||
@apply text-muted font-normal;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,19 @@
|
|||
if (oldLength !== files.files.length) goto("/convert");
|
||||
};
|
||||
|
||||
const uploadFiles = () => {
|
||||
const uploadFiles = async () => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.multiple = true;
|
||||
input.accept = converters
|
||||
// filter converters to ones where await converter.valid() is true
|
||||
const filteredConverters = (
|
||||
await Promise.all(
|
||||
converters.map(async (c) => {
|
||||
if (await c.valid()) return c;
|
||||
}),
|
||||
)
|
||||
).filter((c) => typeof c !== "undefined");
|
||||
input.accept = filteredConverters
|
||||
.map((c) => c.supportedFormats.join(","))
|
||||
.join(",");
|
||||
input.onchange = (e) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const GITHUB_URL = 'https://github.com/VERT-sh/VERT';
|
||||
export const GITHUB_API_URL = 'https://api.github.com/repos/VERT-sh/VERT';
|
||||
|
||||
export const DISCORD_URL = 'https://discord.gg/kqevGxYPak';
|
||||
export const GITHUB_URL_VERT = "https://github.com/VERT-sh/VERT";
|
||||
export const GITHUB_URL_VERTD = "https://github.com/VERT-sh/vertd";
|
||||
export const GITHUB_API_URL = "https://api.github.com/repos/VERT-sh/VERT";
|
||||
export const DISCORD_URL = "https://discord.gg/kqevGxYPak";
|
||||
|
|
|
|||
|
|
@ -28,4 +28,8 @@ export class Converter {
|
|||
): Promise<VertFile> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public async valid(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { FFmpegConverter } from "./ffmpeg.svelte";
|
||||
//import { VertdConverter } from "./vertd.svelte";
|
||||
import { VertdConverter } from "./vertd.svelte";
|
||||
import { VipsConverter } from "./vips.svelte";
|
||||
|
||||
export const converters = [
|
||||
new VipsConverter(),
|
||||
new FFmpegConverter(),
|
||||
//new VertdConverter(),
|
||||
new VertdConverter(),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { log } from "$lib/logger";
|
||||
import { Settings } from "$lib/sections/settings/index.svelte";
|
||||
import { VertFile } from "$lib/types";
|
||||
import { Converter } from "./converter.svelte";
|
||||
|
||||
|
|
@ -25,13 +26,15 @@ interface UploadResponse {
|
|||
|
||||
interface RouteMap {
|
||||
"/api/upload": UploadResponse;
|
||||
"/api/version": string;
|
||||
}
|
||||
|
||||
const vertdFetch = async <U extends keyof RouteMap>(
|
||||
url: U,
|
||||
options: RequestInit,
|
||||
): Promise<RouteMap[U]> => {
|
||||
const res = await fetch(`http://127.0.0.1:8080${url}`, options);
|
||||
const domain = Settings.instance.settings.vertdURL;
|
||||
const res = await fetch(`${domain}${url}`, options);
|
||||
const text = await res.text();
|
||||
let json: VertdResponse<RouteMap[U]> = null!;
|
||||
try {
|
||||
|
|
@ -99,7 +102,8 @@ export class VertdConverter extends Converter {
|
|||
public ready = $state(false);
|
||||
public reportsProgress = true;
|
||||
public supportedFormats = [".mkv", ".mp4", ".webm", ".avi"];
|
||||
private log: (msg: string) => void = () => {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private log: (...msg: any[]) => void = () => {};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -126,7 +130,10 @@ export class VertdConverter extends Converter {
|
|||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const ws = new WebSocket(`ws://localhost:8080/api/ws`);
|
||||
const apiUrl = Settings.instance.settings.vertdURL;
|
||||
const ws = new WebSocket(
|
||||
`ws://${apiUrl.replace("http://", "").replace("https://", "")}/api/ws`,
|
||||
);
|
||||
ws.onopen = () => {
|
||||
this.log("opened ws connection to vertd");
|
||||
const msg: StartJobMessage = {
|
||||
|
|
@ -156,7 +163,7 @@ export class VertdConverter extends Converter {
|
|||
case "jobFinished": {
|
||||
this.log("job finished");
|
||||
ws.close();
|
||||
const url = `http://localhost:8080/api/download/${msg.data.jobId}/${uploadRes.auth}`;
|
||||
const url = `${apiUrl}/api/download/${msg.data.jobId}/${uploadRes.auth}`;
|
||||
this.log(`downloading from ${url}`);
|
||||
const res = await fetch(url).then((res) => res.blob());
|
||||
resolve(
|
||||
|
|
@ -178,4 +185,20 @@ export class VertdConverter extends Converter {
|
|||
};
|
||||
});
|
||||
}
|
||||
|
||||
public async valid(): Promise<boolean> {
|
||||
if (!Settings.instance.settings.vertdURL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await vertdFetch("/api/version", {
|
||||
method: "GET",
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
this.log(e as unknown as string);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import Panel from "$lib/components/visual/Panel.svelte";
|
||||
import { HeartHandshakeIcon } from "lucide-svelte";
|
||||
import { GITHUB_URL } from "$lib/consts";
|
||||
import { GITHUB_URL_VERT } from "$lib/consts";
|
||||
|
||||
let { mainContribs, ghContribs } = $props();
|
||||
</script>
|
||||
|
|
@ -64,7 +64,7 @@
|
|||
Big thanks to all these people for helping out!
|
||||
<a
|
||||
class="text-blue-500 font-normal hover:underline"
|
||||
href={GITHUB_URL}
|
||||
href={GITHUB_URL_VERT}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
|
@ -76,7 +76,7 @@
|
|||
Seems like no one has contributed yet...
|
||||
<a
|
||||
class="text-blue-500 font-normal hover:underline"
|
||||
href={GITHUB_URL}
|
||||
href={GITHUB_URL_VERT}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import Panel from "$lib/components/visual/Panel.svelte";
|
||||
import { DISCORD_URL, GITHUB_URL } from "$lib/consts";
|
||||
import { DISCORD_URL, GITHUB_URL_VERT } from "$lib/consts";
|
||||
import { GithubIcon, LinkIcon, MessageCircleMoreIcon } from "lucide-svelte";
|
||||
</script>
|
||||
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
Discord
|
||||
</a>
|
||||
<a
|
||||
href={GITHUB_URL}
|
||||
href={GITHUB_URL_VERT}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn flex-1 gap-2 p-4 rounded-full bg-button text-black dynadark:text-white flex items-center justify-center"
|
||||
|
|
|
|||
|
|
@ -2,38 +2,14 @@
|
|||
import { browser } from "$app/environment";
|
||||
import FancyTextInput from "$lib/components/functional/FancyInput.svelte";
|
||||
import Panel from "$lib/components/visual/Panel.svelte";
|
||||
import { GITHUB_URL_VERTD } from "$lib/consts";
|
||||
import { log } from "$lib/logger";
|
||||
import { addToast } from "$lib/store/ToastProvider";
|
||||
import { RefreshCwIcon, SaveAllIcon } from "lucide-svelte";
|
||||
import { onMount } from "svelte";
|
||||
import type { Settings } from "./index.svelte";
|
||||
|
||||
// let filenameFormat = "VERT_%name%";
|
||||
let settings = $state({
|
||||
filenameFormat: "VERT_%name%",
|
||||
});
|
||||
|
||||
function save() {
|
||||
log(["settings"], "saving settings");
|
||||
if (!browser) return;
|
||||
try {
|
||||
localStorage.setItem("settings", JSON.stringify(settings));
|
||||
addToast("success", "settings saved!");
|
||||
} catch (error) {
|
||||
log(["settings", "error"], `failed to save settings: ${error}`);
|
||||
addToast("error", "Failed to save settings!");
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const savedSettings = localStorage.getItem("settings");
|
||||
if (savedSettings) {
|
||||
const parsedSettings = JSON.parse(savedSettings);
|
||||
settings = {
|
||||
...settings,
|
||||
...parsedSettings,
|
||||
};
|
||||
}
|
||||
});
|
||||
const { settings }: { settings: Settings } = $props();
|
||||
</script>
|
||||
|
||||
<Panel class="flex flex-col gap-8 p-6">
|
||||
|
|
@ -67,32 +43,11 @@
|
|||
</div>
|
||||
<FancyTextInput
|
||||
placeholder="VERT_%name%"
|
||||
bind:value={settings.filenameFormat}
|
||||
bind:value={settings.settings.filenameFormat}
|
||||
extension=".ext"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base font-bold">Second option</p>
|
||||
<p class="text-sm text-muted font-normal">
|
||||
This is just a sample option. This should not show up on
|
||||
the live website. JOVANN, DO NOT ADD THIS TO THE LIVE
|
||||
WEBSITE. PLEASE. JOVANN!!!!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
onclick={save}
|
||||
class="w-fit btn px-6 py-4 bg-accent text-black flex items-center justify-center"
|
||||
>
|
||||
<SaveAllIcon size="24" class="inline-block mr-2" />
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
<script lang="ts">
|
||||
import { browser } from "$app/environment";
|
||||
import FancyTextInput from "$lib/components/functional/FancyInput.svelte";
|
||||
import Panel from "$lib/components/visual/Panel.svelte";
|
||||
import { GITHUB_URL_VERTD } from "$lib/consts";
|
||||
import { RefreshCwIcon, SaveAllIcon, ServerIcon } from "lucide-svelte";
|
||||
import type { Settings } from "./index.svelte";
|
||||
|
||||
const { settings }: { settings: Settings } = $props();
|
||||
</script>
|
||||
|
||||
<Panel class="flex flex-col gap-8 p-6">
|
||||
<div class="flex flex-col gap-3">
|
||||
<h2 class="text-2xl font-bold">
|
||||
<ServerIcon
|
||||
size="40"
|
||||
class="inline-block -mt-1 mr-2 bg-accent-red p-2 rounded-full overflow-visible"
|
||||
color="black"
|
||||
/>
|
||||
<code>vertd</code>
|
||||
</h2>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-sm text-muted font-normal">
|
||||
VERT allows fully functional video conversion via the
|
||||
<code>vertd</code> project. It acts as an FFmpeg wrapper on
|
||||
a given server, allowing for GPU accelerated local* video
|
||||
conversion. We currently don't provide our own instance due
|
||||
to upkeep costs of servers with the necessary hardware for
|
||||
speedy conversion. You can host your own instance by
|
||||
downloading the binaries
|
||||
<a href={GITHUB_URL_VERTD} target="_blank">here</a>.
|
||||
</p>
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base font-bold">Instance URL</p>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="http://localhost:24153"
|
||||
bind:value={settings.settings.vertdURL}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
export { default as Appearance } from "./Appearance.svelte";
|
||||
export { default as Conversion } from "./Conversion.svelte";
|
||||
export { default as Vertd } from "./Vertd.svelte";
|
||||
|
||||
export interface ISettings {
|
||||
filenameFormat: string;
|
||||
vertdURL: string;
|
||||
}
|
||||
|
||||
export class Settings {
|
||||
public static instance = new Settings();
|
||||
|
||||
public settings: ISettings = $state({
|
||||
filenameFormat: "VERT_%name%",
|
||||
vertdURL: "",
|
||||
});
|
||||
|
||||
public save() {
|
||||
localStorage.setItem("settings", JSON.stringify(this.settings));
|
||||
}
|
||||
|
||||
public load() {
|
||||
const ls = localStorage.getItem("settings");
|
||||
if (!ls) return;
|
||||
const settings: ISettings = JSON.parse(ls);
|
||||
this.settings = {
|
||||
...this.settings,
|
||||
...settings,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { default as Appearance } from "./Appearance.svelte";
|
||||
export { default as Conversion } from "./Conversion.svelte";
|
||||
|
|
@ -28,9 +28,10 @@
|
|||
import { quintOut } from "svelte/easing";
|
||||
import "../app.scss";
|
||||
import { writable } from "svelte/store";
|
||||
import { DISCORD_URL, GITHUB_URL } from "$lib/consts";
|
||||
import { DISCORD_URL, GITHUB_URL_VERT } from "$lib/consts";
|
||||
import { type Toast as ToastType, toasts } from "$lib/store/ToastProvider";
|
||||
import Toast from "$lib/components/visual/Toast.svelte";
|
||||
import { Settings } from "$lib/sections/settings/index.svelte";
|
||||
let { children } = $props();
|
||||
|
||||
let shouldGoBack = writable(false);
|
||||
|
|
@ -123,6 +124,10 @@
|
|||
goingLeft = false;
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
Settings.instance.load();
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
|
@ -239,7 +244,7 @@
|
|||
class="w-full h-full"
|
||||
items={{
|
||||
//"Privacy policy": "#",
|
||||
"Source code": GITHUB_URL,
|
||||
"Source code": GITHUB_URL_VERT,
|
||||
"Discord server": DISCORD_URL,
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,47 @@
|
|||
<script lang="ts">
|
||||
import * as Settings from "$lib/sections/settings";
|
||||
import { browser } from "$app/environment";
|
||||
import { log } from "$lib/logger";
|
||||
import * as Settings from "$lib/sections/settings/index.svelte";
|
||||
import { addToast } from "$lib/store/ToastProvider";
|
||||
import { SettingsIcon } from "lucide-svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let isInitial = $state(true);
|
||||
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
if (isInitial) {
|
||||
isInitial = false;
|
||||
return;
|
||||
}
|
||||
const savedSettings = localStorage.getItem("settings");
|
||||
if (savedSettings) {
|
||||
const parsedSettings = JSON.parse(savedSettings);
|
||||
if (parsedSettings === Settings.Settings.instance.settings) return;
|
||||
}
|
||||
|
||||
log(["settings"], "saving settings");
|
||||
try {
|
||||
localStorage.setItem(
|
||||
"settings",
|
||||
JSON.stringify(Settings.Settings.instance.settings),
|
||||
);
|
||||
} catch (error) {
|
||||
log(["settings", "error"], `failed to save settings: ${error}`);
|
||||
addToast("error", "Failed to save settings!");
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
const savedSettings = localStorage.getItem("settings");
|
||||
if (savedSettings) {
|
||||
const parsedSettings = JSON.parse(savedSettings);
|
||||
Settings.Settings.instance.settings = {
|
||||
...Settings.Settings.instance.settings,
|
||||
...parsedSettings,
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col h-full items-center">
|
||||
|
|
@ -13,13 +53,13 @@
|
|||
<div
|
||||
class="w-full max-w-[1280px] flex flex-col md:flex-row gap-4 p-4 md:px-4 md:py-0"
|
||||
>
|
||||
<!-- Why VERT? & Credits -->
|
||||
<div class="flex flex-col gap-4 flex-1">
|
||||
<Settings.Conversion />
|
||||
<Settings.Conversion settings={Settings.Settings.instance} />
|
||||
<Settings.Vertd settings={Settings.Settings.instance} />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-4 flex-1">
|
||||
<Settings.Appearance />
|
||||
|
||||
<div class="flex flex-col gap-4 flex-1">
|
||||
<Settings.Appearance />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue