cobalt / web /src /lib /download.ts
playingapi's picture
Upload 376 files
43a06dc verified
import { get } from "svelte/store";
import settings from "$lib/state/settings";
import { device } from "$lib/device";
import { t } from "$lib/i18n/translations";
import { createDialog } from "$lib/state/dialogs";
import type { DialogInfo } from "$lib/types/dialog";
import type { CobaltFileUrlType } from "$lib/types/api";
type DownloadFileParams = {
url?: string,
file?: File,
urlType?: CobaltFileUrlType,
}
type SavingDialogParams = {
url?: string,
file?: File,
body?: string,
urlType?: CobaltFileUrlType,
}
const openSavingDialog = ({ url, file, body, urlType }: SavingDialogParams) => {
const dialogData: DialogInfo = {
type: "saving",
id: "saving",
file,
url,
urlType,
}
if (body) dialogData.bodyText = body;
createDialog(dialogData)
}
export const openFile = (file: File) => {
const a = document.createElement("a");
const url = URL.createObjectURL(file);
a.href = url;
a.download = file.name;
a.click();
URL.revokeObjectURL(url);
}
export const shareFile = async (file: File) => {
return await navigator?.share({
files: [
new File([file], file.name, {
type: file.type,
}),
],
});
}
export const openURL = (url: string) => {
if (!['http:', 'https:'].includes(new URL(url).protocol)) {
return alert('error: invalid url!');
}
const open = window.open(url, "_blank");
/* if new tab got blocked by user agent, show a saving dialog */
if (!open) {
return openSavingDialog({
url,
body: get(t)("dialog.saving.blocked")
});
}
}
export const shareURL = async (url: string) => {
return await navigator?.share({ url });
}
export const copyURL = async (url: string) => {
return await navigator?.clipboard?.writeText(url);
}
export const downloadFile = ({ url, file, urlType }: DownloadFileParams) => {
if (!url && !file) throw new Error("attempted to download void");
const pref = get(settings).save.savingMethod;
if (pref === "ask") {
return openSavingDialog({ url, file, urlType });
}
/*
user actions (such as invoke share, open new tab) have expiration.
in webkit, for example, that timeout is 5 seconds.
https://github.com/WebKit/WebKit/blob/b838f8bb/Source/WebCore/page/LocalDOMWindow.cpp#L167
navigator.userActivation.isActive makes sure that we're still able to
invoke an action without the user agent interrupting it.
if not, we show a saving dialog for user to re-invoke that action.
if browser is old or doesn't support this API, we just assume that it expired.
*/
if (!navigator?.userActivation?.isActive) {
return openSavingDialog({
url,
file,
body: get(t)("dialog.saving.timeout"),
urlType
});
}
try {
if (file) {
if (pref === "share" && device.supports.share) {
return shareFile(file);
} else if (pref === "download" && device.supports.directDownload) {
return openFile(file);
}
}
if (url) {
if (pref === "share" && device.supports.share) {
return shareURL(url);
} else if (pref === "download" && device.supports.directDownload
&& !(device.is.iOS && urlType === "redirect")) {
return openURL(url);
} else if (pref === "copy" && !file) {
return copyURL(url);
}
}
} catch { /* catch & ignore */ }
return openSavingDialog({ url, file, urlType });
}