mirror of https://github.com/VERT-sh/VERT.git
feat: generic server upload warning
added a generic server upload warning, turning it into a toast w/ options instead of a dialog. fixed some hardcoded translations & tooltips
This commit is contained in:
parent
d18fe38832
commit
ba6507b7e6
|
|
@ -44,7 +44,7 @@
|
|||
"partial_support": "This format can only be converted as {direction}.",
|
||||
"direction_input": "input (from)",
|
||||
"direction_output": "output (to)",
|
||||
"video_server_processing": "Video uploads to a server for processing by default, learn how to set it up locally here."
|
||||
"video_server_processing": "When possible, VERT converts videos locally in your browser. Some conversions may require server-side processing, learn how to set it up locally here."
|
||||
}
|
||||
},
|
||||
"convert": {
|
||||
|
|
@ -62,9 +62,10 @@
|
|||
"large_file_warning": "Due to browser / device limitations, video to audio conversion is disabled for this file as it is larger than {limit}GB. We recommend using Firefox or Safari for files of this size since they have less limitations.",
|
||||
"external_warning": {
|
||||
"title": "External server warning",
|
||||
"text": "If you choose to convert into a video format, those files will be uploaded to an external server to be converted. Do you want to continue?",
|
||||
"yes": "Yes",
|
||||
"no": "No"
|
||||
"text": "Converting {filename} with its current settings is not supported locally and requires server-side processing. Do you want to continue?",
|
||||
"yes": "Convert on server",
|
||||
"no": "Cancel conversion",
|
||||
"dont_show_again": "Don't show again"
|
||||
},
|
||||
"panel": {
|
||||
"convert_all": "Convert all",
|
||||
|
|
@ -149,6 +150,7 @@
|
|||
"errors": {
|
||||
"cant_convert": "We can't convert this file.",
|
||||
"converter_fallback": {
|
||||
"title": "Change converter?",
|
||||
"body": "Conversion failed for {filename}. Would you like to try the next compatible converter {converter}?",
|
||||
"yes": "Next converter",
|
||||
"no": "Cancel conversion",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { m } from "$lib/paraglide/messages";
|
||||
|
||||
type Additional = {
|
||||
fileName: string;
|
||||
filename: string;
|
||||
nextConverter: string;
|
||||
onNext: () => void | Promise<void>;
|
||||
onCancel: () => void;
|
||||
|
|
@ -10,13 +10,13 @@
|
|||
|
||||
let { additional }: { additional: Additional } = $props();
|
||||
|
||||
export const title = "An error occurred";
|
||||
export const title = m["convert.errors.converter_fallback.title"]();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-black">
|
||||
{m["convert.errors.converter_fallback.body"]({
|
||||
filename: additional.fileName,
|
||||
filename: additional.filename,
|
||||
converter: additional.nextConverter,
|
||||
})}
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
<script lang="ts" module>
|
||||
export interface ServerUploadWarningProps {
|
||||
filename: string;
|
||||
onProceed: () => void;
|
||||
onCancel: () => void;
|
||||
onDontShowAgain: () => void;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { m } from "$lib/paraglide/messages";
|
||||
import type { ToastProps } from "$lib/util/toast.svelte";
|
||||
|
||||
const toast: ToastProps<ServerUploadWarningProps> = $props();
|
||||
|
||||
export const title = m["convert.external_warning.title"]();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-black">
|
||||
{m["convert.external_warning.text"]({
|
||||
filename: toast.additional.filename,
|
||||
})}
|
||||
</p>
|
||||
<div class="flex flex-col gap-2">
|
||||
<button
|
||||
onclick={toast.additional.onDontShowAgain}
|
||||
class="btn rounded-lg h-fit py-2 w-full bg-accent-blue text-black"
|
||||
>
|
||||
{m["convert.external_warning.dont_show_again"]()}
|
||||
</button>
|
||||
<div class="flex gap-4">
|
||||
<button
|
||||
onclick={toast.additional.onProceed}
|
||||
class="btn rounded-lg h-fit py-2 w-full bg-accent-red-alt text-white"
|
||||
>
|
||||
{m["convert.external_warning.yes"]()}
|
||||
</button>
|
||||
<button
|
||||
onclick={toast.additional.onCancel}
|
||||
class="btn rounded-lg h-fit py-2 w-full"
|
||||
>
|
||||
{m["convert.external_warning.no"]()}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
from?: string;
|
||||
to?: string;
|
||||
errorMessage?: string;
|
||||
fileName?: string;
|
||||
filename?: string;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
let submitting = $state(false);
|
||||
|
||||
export const title = "An error occurred";
|
||||
export const title = m["convert.errors.vertd_generic_title"]();
|
||||
|
||||
const remove = () => {
|
||||
ToastManager.remove(toast.id);
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@
|
|||
<style lang="postcss">
|
||||
.tooltip {
|
||||
--border-size: 1px;
|
||||
@apply fixed bg-panel-alt text-foreground border border-stone-400 dynadark:border-white drop-shadow-lg text-xs rounded-full pointer-events-none z-[999] max-w-xs break-words whitespace-normal;
|
||||
@apply px-5 py-2.5;
|
||||
@apply fixed bg-panel-alt text-foreground border border-stone-400 dynadark:border-white drop-shadow-lg text-xs pointer-events-none z-[999] max-w-[200px] break-words whitespace-normal;
|
||||
@apply px-3.5 py-2 rounded-xl;
|
||||
}
|
||||
|
||||
.tooltip-top {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { error, log } from "$lib/util/logger";
|
|||
import { VertFile } from "$lib/types";
|
||||
import { parseBlob, selectCover } from "music-metadata";
|
||||
import { writable } from "svelte/store";
|
||||
import { addDialog } from "./DialogProvider";
|
||||
import PQueue from "p-queue";
|
||||
import { getLocale, setLocale } from "$lib/paraglide/runtime";
|
||||
import { m } from "$lib/paraglide/messages";
|
||||
|
|
@ -236,7 +235,6 @@ class Files {
|
|||
}
|
||||
}
|
||||
|
||||
private _warningShown = false;
|
||||
private async _add(file: VertFile | File) {
|
||||
if (file instanceof VertFile) {
|
||||
this.files.push(file);
|
||||
|
|
@ -302,43 +300,6 @@ class Files {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: only show if vertd is needed/requested
|
||||
const isServerVideo = convName === "vertd";
|
||||
const acceptedExternalWarning =
|
||||
localStorage.getItem("acceptedExternalWarning") === "true";
|
||||
if (isServerVideo && !acceptedExternalWarning && !this._warningShown) {
|
||||
this._warningShown = true;
|
||||
const title = m["convert.external_warning.title"]();
|
||||
const message = m["convert.external_warning.text"]();
|
||||
const buttons = [
|
||||
{
|
||||
text: m["convert.external_warning.no"](),
|
||||
action: () => {
|
||||
this.files = [
|
||||
...this.files.filter(
|
||||
(f) =>
|
||||
!f.converters
|
||||
.map((c) => c.name)
|
||||
.includes("vertd"),
|
||||
),
|
||||
];
|
||||
this._warningShown = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: m["convert.external_warning.yes"](),
|
||||
action: () => {
|
||||
localStorage.setItem(
|
||||
"acceptedExternalWarning",
|
||||
"true",
|
||||
);
|
||||
this._warningShown = false;
|
||||
},
|
||||
},
|
||||
];
|
||||
addDialog(title, message, buttons, "warning");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -378,7 +339,7 @@ class Files {
|
|||
if (this.files.length === 0) return;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const dlFiles: any[] = [];
|
||||
const fileNames: string[] = [];
|
||||
const filenames: string[] = [];
|
||||
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
const file = this.files[i];
|
||||
|
|
@ -392,7 +353,7 @@ class Files {
|
|||
let to = result.to;
|
||||
if (!to.startsWith(".")) to = `.${to}`;
|
||||
|
||||
fileNames.push(file.file.name.replace(/\.[^/.]+$/, "") + to);
|
||||
filenames.push(file.file.name.replace(/\.[^/.]+$/, "") + to);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
|
|
@ -401,19 +362,19 @@ class Files {
|
|||
|
||||
if (!result) continue;
|
||||
|
||||
let fileName = fileNames[i];
|
||||
let filename = filenames[i];
|
||||
|
||||
// check if this filename appears more than once
|
||||
const isDuplicate = fileNames.filter((name) => name === fileName).length > 1;
|
||||
const isDuplicate = filenames.filter((name) => name === filename).length > 1;
|
||||
if (isDuplicate) {
|
||||
const nameParts = fileName.lastIndexOf(".");
|
||||
const nameWithoutExt = fileName.substring(0, nameParts);
|
||||
const ext = fileName.substring(nameParts);
|
||||
fileName = `${nameWithoutExt} (${i + 1})${ext}`;
|
||||
const nameParts = filename.lastIndexOf(".");
|
||||
const nameWithoutExt = filename.substring(0, nameParts);
|
||||
const ext = filename.substring(nameParts);
|
||||
filename = `${nameWithoutExt} (${i + 1})${ext}`;
|
||||
}
|
||||
|
||||
dlFiles.push({
|
||||
name: fileName,
|
||||
name: filename,
|
||||
lastModified: Date.now(),
|
||||
input: await result.file.arrayBuffer(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { ToastManager } from "$lib/util/toast.svelte";
|
|||
import type { Component } from "svelte";
|
||||
import { MAX_ARRAY_BUFFER_SIZE } from "$lib/store/index.svelte";
|
||||
import FallbackToast from "$lib/components/functional/popups/FallbackToast.svelte";
|
||||
import ServerUploadWarning from "$lib/components/functional/popups/ServerUploadWarning.svelte";
|
||||
import type {
|
||||
ConversionSettings,
|
||||
SettingDefinition,
|
||||
|
|
@ -41,6 +42,7 @@ export class VertFile {
|
|||
private fallbackToastId: number | null = null;
|
||||
private attemptedConverters = new Set<string>();
|
||||
private retryingFallback = false;
|
||||
private vertdWarningToastId: number | null = null;
|
||||
|
||||
public isZip = $state(() => this.from === ".zip");
|
||||
|
||||
|
|
@ -168,6 +170,13 @@ export class VertFile {
|
|||
}
|
||||
|
||||
if (!converter) throw new Error("No converter found");
|
||||
|
||||
const canProceed = await this.confirmServerWarning(converter);
|
||||
if (!canProceed) {
|
||||
this.cancelled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.attemptedConverters.add(converter.name);
|
||||
log(["file", "convert"], `using converter: ${converter.name}`);
|
||||
|
||||
|
|
@ -215,7 +224,7 @@ export class VertFile {
|
|||
disappearing: false,
|
||||
message: FallbackToast,
|
||||
additional: {
|
||||
fileName: this.file.name,
|
||||
filename: this.file.name,
|
||||
nextConverter: nextConverter.name,
|
||||
onNext: async () => {
|
||||
if (this.fallbackToastId !== null)
|
||||
|
|
@ -262,6 +271,47 @@ export class VertFile {
|
|||
return res;
|
||||
}
|
||||
|
||||
private async confirmServerWarning(converter: Converter): Promise<boolean> {
|
||||
if (converter.name !== "vertd") return true;
|
||||
if (localStorage.getItem("acceptedExternalWarning") === "true")
|
||||
return true;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let resolved = false;
|
||||
|
||||
const finish = (shouldProceed: boolean) => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
if (this.vertdWarningToastId !== null)
|
||||
ToastManager.remove(this.vertdWarningToastId);
|
||||
this.vertdWarningToastId = null;
|
||||
resolve(shouldProceed);
|
||||
};
|
||||
|
||||
if (this.vertdWarningToastId !== null)
|
||||
ToastManager.remove(this.vertdWarningToastId);
|
||||
|
||||
this.vertdWarningToastId = ToastManager.add({
|
||||
type: "warning",
|
||||
disappearing: false,
|
||||
message: ServerUploadWarning,
|
||||
additional: {
|
||||
filename: this.file.name,
|
||||
onProceed: () => {
|
||||
finish(true);
|
||||
},
|
||||
onCancel: () => {
|
||||
finish(false);
|
||||
},
|
||||
onDontShowAgain: () => {
|
||||
localStorage.setItem("acceptedExternalWarning", "true");
|
||||
finish(true);
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async convertZip(converter: Converter): Promise<VertFile> {
|
||||
const { extractZip, createZip } = await import("$lib/util/zip");
|
||||
const { default: PQueue } = await import("p-queue");
|
||||
|
|
|
|||
Loading…
Reference in New Issue