mirror of
https://github.com/wukko/cobalt.git
synced 2025-05-05 16:24:31 +02:00
web/DownloadButton: extract api interaction logic into a lib
download button state is now stored, well, in a state
This commit is contained in:
parent
1c34d2daff
commit
91f5d63b93
@ -11,6 +11,7 @@
|
||||
import dialogs from "$lib/state/dialogs";
|
||||
import { link } from "$lib/state/omnibox";
|
||||
import { updateSetting } from "$lib/state/settings";
|
||||
import { savingHandler } from "$lib/api/saving-handler";
|
||||
import { pasteLinkFromClipboard } from "$lib/clipboard";
|
||||
import { turnstileEnabled, turnstileSolved } from "$lib/state/turnstile";
|
||||
|
||||
@ -75,7 +76,7 @@
|
||||
|
||||
if (!isBotCheckOngoing) {
|
||||
await tick(); // wait for button to render
|
||||
downloadButton.download($link);
|
||||
savingHandler($link);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -94,7 +95,7 @@
|
||||
}
|
||||
|
||||
if (e.key === "Enter" && validLink($link) && isFocused) {
|
||||
downloadButton.download($link);
|
||||
savingHandler($link);
|
||||
}
|
||||
|
||||
if (["Escape", "Clear"].includes(e.key) && isFocused) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import "@fontsource-variable/noto-sans-mono";
|
||||
|
||||
import API from "$lib/api/api";
|
||||
import { onDestroy } from "svelte";
|
||||
import { t } from "$lib/i18n/translations";
|
||||
import { createDialog } from "$lib/state/dialogs";
|
||||
import { downloadFile } from "$lib/download";
|
||||
import { savingHandler } from "$lib/api/saving-handler";
|
||||
import { downloadButtonState } from "$lib/state/omnibox";
|
||||
|
||||
import type { DialogInfo } from "$lib/types/dialog";
|
||||
import type { CobaltDownloadButtonState } from "$lib/types/omnibox";
|
||||
|
||||
export let url: string;
|
||||
export let disabled = false;
|
||||
@ -15,22 +15,9 @@
|
||||
$: buttonText = ">>";
|
||||
$: buttonAltText = $t("a11y.save.download");
|
||||
|
||||
let defaultErrorPopup: DialogInfo = {
|
||||
id: "save-error",
|
||||
type: "small",
|
||||
meowbalt: "error",
|
||||
buttons: [
|
||||
{
|
||||
text: $t("button.gotit"),
|
||||
main: true,
|
||||
action: () => {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
type DownloadButtonState = "idle" | "think" | "check" | "done" | "error";
|
||||
|
||||
const changeDownloadButton = (state: DownloadButtonState) => {
|
||||
const unsubscribe = downloadButtonState.subscribe((state: CobaltDownloadButtonState) => {
|
||||
disabled = state !== "idle";
|
||||
loading = state === "think" || state === "check";
|
||||
|
||||
@ -56,107 +43,17 @@
|
||||
// transition back to idle after some period of time.
|
||||
const final: DownloadButtonState[] = ["done", "error"];
|
||||
if (final.includes(state)) {
|
||||
setTimeout(() => changeDownloadButton("idle"), 1500);
|
||||
setTimeout(() => downloadButtonState.set("idle"), 1500);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export const download = async (link: string) => {
|
||||
changeDownloadButton("think");
|
||||
|
||||
const response = await API.request(link);
|
||||
|
||||
if (!response) {
|
||||
changeDownloadButton("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
bodyText: $t("error.api.unreachable"),
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === "error") {
|
||||
changeDownloadButton("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
bodyText: $t(response.error.code, response?.error?.context),
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === "redirect") {
|
||||
changeDownloadButton("done");
|
||||
|
||||
return downloadFile({
|
||||
url: response.url,
|
||||
urlType: "redirect",
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === "tunnel") {
|
||||
changeDownloadButton("check");
|
||||
|
||||
const probeResult = await API.probeCobaltTunnel(response.url);
|
||||
|
||||
if (probeResult === 200) {
|
||||
changeDownloadButton("done");
|
||||
|
||||
return downloadFile({
|
||||
url: response.url,
|
||||
});
|
||||
} else {
|
||||
changeDownloadButton("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
bodyText: $t("error.tunnel.probe"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (response.status === "picker") {
|
||||
changeDownloadButton("done");
|
||||
const buttons = [
|
||||
{
|
||||
text: $t("button.done"),
|
||||
main: true,
|
||||
action: () => {},
|
||||
},
|
||||
];
|
||||
|
||||
if (response.audio) {
|
||||
const pickerAudio = response.audio;
|
||||
buttons.unshift({
|
||||
text: $t("button.download.audio"),
|
||||
main: false,
|
||||
action: () => {
|
||||
downloadFile({
|
||||
url: pickerAudio,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return createDialog({
|
||||
id: "download-picker",
|
||||
type: "picker",
|
||||
items: response.picker,
|
||||
buttons,
|
||||
});
|
||||
}
|
||||
|
||||
changeDownloadButton("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
bodyText: $t("error.api.unknown_response"),
|
||||
});
|
||||
};
|
||||
onDestroy(() => unsubscribe());
|
||||
</script>
|
||||
|
||||
<button
|
||||
id="download-button"
|
||||
{disabled}
|
||||
on:click={() => download(url)}
|
||||
on:click={() => savingHandler(url)}
|
||||
aria-label={buttonAltText}
|
||||
>
|
||||
<span id="download-state">{buttonText}</span>
|
||||
|
123
web/src/lib/api/saving-handler.ts
Normal file
123
web/src/lib/api/saving-handler.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import API from "$lib/api/api";
|
||||
|
||||
import { get } from "svelte/store";
|
||||
import { t } from "$lib/i18n/translations";
|
||||
import { downloadFile } from "$lib/download";
|
||||
import { createDialog } from "$lib/state/dialogs";
|
||||
import { downloadButtonState } from "$lib/state/omnibox";
|
||||
|
||||
import type { DialogInfo } from "$lib/types/dialog";
|
||||
|
||||
const defaultErrorPopup: DialogInfo = {
|
||||
id: "save-error",
|
||||
type: "small",
|
||||
meowbalt: "error",
|
||||
};
|
||||
|
||||
export const savingHandler = async (link: string) => {
|
||||
downloadButtonState.set("think");
|
||||
|
||||
const errorButtons = [
|
||||
{
|
||||
text: get(t)("button.gotit"),
|
||||
main: true,
|
||||
action: () => { },
|
||||
},
|
||||
];
|
||||
|
||||
const response = await API.request(link);
|
||||
|
||||
if (!response) {
|
||||
downloadButtonState.set("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
buttons: errorButtons,
|
||||
bodyText: get(t)("error.api.unreachable"),
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === "error") {
|
||||
downloadButtonState.set("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
buttons: errorButtons,
|
||||
bodyText: get(t)(response.error.code, response?.error?.context),
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === "redirect") {
|
||||
downloadButtonState.set("done");
|
||||
|
||||
return downloadFile({
|
||||
url: response.url,
|
||||
urlType: "redirect",
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === "tunnel") {
|
||||
downloadButtonState.set("check");
|
||||
|
||||
const probeResult = await API.probeCobaltTunnel(response.url);
|
||||
|
||||
if (probeResult === 200) {
|
||||
downloadButtonState.set("done");
|
||||
|
||||
return downloadFile({
|
||||
url: response.url,
|
||||
});
|
||||
} else {
|
||||
downloadButtonState.set("error");
|
||||
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
buttons: errorButtons,
|
||||
bodyText: get(t)("error.tunnel.probe"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (response.status === "local-processing") {
|
||||
// TODO: actual implementation
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
if (response.status === "picker") {
|
||||
downloadButtonState.set("done");
|
||||
const buttons = [
|
||||
{
|
||||
text: get(t)("button.done"),
|
||||
main: true,
|
||||
action: () => { },
|
||||
},
|
||||
];
|
||||
|
||||
if (response.audio) {
|
||||
const pickerAudio = response.audio;
|
||||
buttons.unshift({
|
||||
text: get(t)("button.download.audio"),
|
||||
main: false,
|
||||
action: () => {
|
||||
downloadFile({
|
||||
url: pickerAudio,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return createDialog({
|
||||
id: "download-picker",
|
||||
type: "picker",
|
||||
items: response.picker,
|
||||
buttons,
|
||||
});
|
||||
}
|
||||
|
||||
downloadButtonState.set("error");
|
||||
return createDialog({
|
||||
...defaultErrorPopup,
|
||||
buttons: errorButtons,
|
||||
bodyText: get(t)("error.api.unknown_response"),
|
||||
});
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import { writable } from "svelte/store";
|
||||
import type { CobaltDownloadButtonState } from "$lib/types/omnibox";
|
||||
|
||||
export const link = writable("");
|
||||
export const downloadButtonState = writable<CobaltDownloadButtonState>("idle");
|
||||
|
1
web/src/lib/types/omnibox.ts
Normal file
1
web/src/lib/types/omnibox.ts
Normal file
@ -0,0 +1 @@
|
||||
export type CobaltDownloadButtonState = "idle" | "think" | "check" | "done" | "error";
|
Loading…
x
Reference in New Issue
Block a user