web: added saving method preference, made downloading resilient

This commit is contained in:
wukko 2024-07-28 18:59:58 +06:00
parent 87adffaf02
commit 5c780a2d2e
No known key found for this signature in database
GPG key ID: 3E30B3F26C7B4AA2
8 changed files with 56 additions and 43 deletions

View file

@ -72,9 +72,12 @@
"metadata.disable.title": "disable file metadata", "metadata.disable.title": "disable file metadata",
"metadata.disable.description": "title, artist, and other info will not be added to the file.", "metadata.disable.description": "title, artist, and other info will not be added to the file.",
"saving.method": "saving method", "saving.title": "saving method",
"saving.ask.title": "ask how to save", "saving.ask": "ask",
"saving.ask.description": "offer several ways to save the file instead of opening it in a new tab.", "saving.download": "download",
"saving.share": "share",
"saving.copy": "copy",
"saving.description": "preferred way of saving the file or link from cobalt. if preferred method is unavailable or something goes wrong, cobalt will ask you what to do next.",
"accessibility": "accessibility", "accessibility": "accessibility",
"accessibility.transparency.title": "reduce visual transparency", "accessibility.transparency.title": "reduce visual transparency",

View file

@ -34,7 +34,7 @@
</h2> </h2>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
{#if !(app.is.installed && device.is.iOS)} {#if device.supports.directDownload}
<VerticalActionButton <VerticalActionButton
id="save-download" id="save-download"
fill fill
@ -46,7 +46,7 @@
</VerticalActionButton> </VerticalActionButton>
{/if} {/if}
{#if navigator.share !== undefined} {#if device.supports.share}
<VerticalActionButton <VerticalActionButton
id="save-share" id="save-share"
fill fill

View file

@ -15,6 +15,12 @@ const installed = window.matchMedia('(display-mode: standalone)').matches;
const reducedMotion = window.matchMedia(`(prefers-reduced-motion: reduce)`).matches; const reducedMotion = window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;
const reducedTransparency = window.matchMedia(`(prefers-reduced-transparency: reduce)`).matches; const reducedTransparency = window.matchMedia(`(prefers-reduced-transparency: reduce)`).matches;
const app = {
is: {
installed
}
}
const device = { const device = {
is: { is: {
iPhone, iPhone,
@ -28,13 +34,12 @@ const device = {
reducedMotion, reducedMotion,
reducedTransparency, reducedTransparency,
}, },
supports: {
share: navigator.share !== undefined,
directDownload: !(installed && iOS),
},
userAgent: navigator.userAgent, userAgent: navigator.userAgent,
} }
const app = {
is: {
installed
}
}
export { device, app }; export { device, app };

View file

@ -1,6 +1,6 @@
import { get } from "svelte/store"; import { get } from "svelte/store";
import { app, device } from "$lib/device"; import { device } from "$lib/device";
import settings from "$lib/state/settings"; import settings from "$lib/state/settings";
import { createDialog } from "$lib/dialogs"; import { createDialog } from "$lib/dialogs";
@ -17,28 +17,20 @@ export const openURL = (url: string) => {
/* if new tab got blocked by user agent, show a saving dialog */ /* if new tab got blocked by user agent, show a saving dialog */
if (!open) { if (!open) {
openSavingDialog(url); return openSavingDialog(url);
} }
} }
export const shareURL = async (url: string) => { export const shareURL = async (url: string) => {
try {
return await navigator?.share({ url }); return await navigator?.share({ url });
} catch {
return false;
}
} }
export const copyURL = async (url: string) => { export const copyURL = async (url: string) => {
try { return await navigator?.clipboard?.writeText(url);
return await navigator?.clipboard.writeText(url);
} catch {
return false;
}
} }
export const downloadFile = (url: string) => { export const downloadFile = (url: string) => {
const savingPreference = get(settings).save.downloadPopup; const pref = get(settings).save.savingMethod;
/* /*
user actions (such as invoke share, open new tab) have expiration. user actions (such as invoke share, open new tab) have expiration.
@ -49,11 +41,20 @@ export const downloadFile = (url: string) => {
invoke an action without the user agent interrupting it. invoke an action without the user agent interrupting it.
if not, we show a saving dialog for user to re-invoke that action. if not, we show a saving dialog for user to re-invoke that action.
*/ */
if (savingPreference || !navigator.userActivation.isActive) {
openSavingDialog(url); if (pref === "ask" || !navigator.userActivation.isActive) {
} else if (device.is.iOS && app.is.installed) { return openSavingDialog(url);
}
try {
if (pref === "share" && device.supports.share) {
return shareURL(url); return shareURL(url);
} else { } else if (pref === "download" && device.supports.directDownload) {
return openURL(url); return openURL(url);
} else if (pref === "copy") {
return copyURL(url);
} }
} catch {}
return openSavingDialog(url);
} }

View file

@ -18,8 +18,8 @@ const defaultSettings: CobaltSettings = {
audioFormat: "mp3", audioFormat: "mp3",
disableMetadata: false, disableMetadata: false,
downloadMode: "auto", downloadMode: "auto",
downloadPopup: false,
filenameStyle: "classic", filenameStyle: "classic",
savingMethod: "download",
tiktokH265: false, tiktokH265: false,
tiktokFullAudio: false, tiktokFullAudio: false,
twitterGif: false, twitterGif: false,

View file

@ -10,7 +10,6 @@ const oldSwitcherValues = {
const oldCheckboxes = [ const oldCheckboxes = [
'audioMode', 'audioMode',
'downloadPopup',
'fullTikTokAudio', 'fullTikTokAudio',
'muteAudio', 'muteAudio',
'reduceTransparency', 'reduceTransparency',
@ -101,7 +100,6 @@ export const migrateOldSettings = () => {
filenameStyle: getLiteral('filenamePattern'), filenameStyle: getLiteral('filenamePattern'),
tiktokFullAudio: getBool('fullTikTokAudio'), tiktokFullAudio: getBool('fullTikTokAudio'),
tiktokH265: getBool('tiktokH265'), tiktokH265: getBool('tiktokH265'),
downloadPopup: getBool('downloadPopup'),
disableMetadata: getBool('disableMetadata'), disableMetadata: getBool('disableMetadata'),
twitterGif: getBool('twitterGif'), twitterGif: getBool('twitterGif'),
youtubeDubBrowserLang: getBool('ytDub'), youtubeDubBrowserLang: getBool('ytDub'),

View file

@ -7,6 +7,7 @@ export const downloadModeOptions = ["auto", "audio", "mute"] as const;
export const filenameStyleOptions = ["classic", "basic", "pretty", "nerdy"] as const; export const filenameStyleOptions = ["classic", "basic", "pretty", "nerdy"] as const;
export const videoQualityOptions = ["max", "2160", "1440", "1080", "720", "480", "360", "240", "144"] as const; export const videoQualityOptions = ["max", "2160", "1440", "1080", "720", "480", "360", "240", "144"] as const;
export const youtubeVideoCodecOptions = ["h264", "av1", "vp9"] as const; export const youtubeVideoCodecOptions = ["h264", "av1", "vp9"] as const;
export const savingMethodOptions = ["ask", "download", "share", "copy"] as const;
type CobaltSettingsAppearance = { type CobaltSettingsAppearance = {
theme: typeof themeOptions[number], theme: typeof themeOptions[number],
@ -28,8 +29,8 @@ type CobaltSettingsSave = {
audioFormat: typeof audioFormatOptions[number], audioFormat: typeof audioFormatOptions[number],
disableMetadata: boolean, disableMetadata: boolean,
downloadMode: typeof downloadModeOptions[number], downloadMode: typeof downloadModeOptions[number],
downloadPopup: boolean,
filenameStyle: typeof filenameStyleOptions[number], filenameStyle: typeof filenameStyleOptions[number],
savingMethod: typeof savingMethodOptions[number],
tiktokH265: boolean, tiktokH265: boolean,
tiktokFullAudio: boolean, tiktokFullAudio: boolean,
twitterGif: boolean, twitterGif: boolean,

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { t } from "$lib/i18n/translations"; import { t } from "$lib/i18n/translations";
import { filenameStyleOptions } from "$lib/types/settings"; import { filenameStyleOptions, savingMethodOptions } from "$lib/types/settings";
import SettingsCategory from "$components/settings/SettingsCategory.svelte"; import SettingsCategory from "$components/settings/SettingsCategory.svelte";
import Switcher from "$components/buttons/Switcher.svelte"; import Switcher from "$components/buttons/Switcher.svelte";
@ -30,6 +30,20 @@
</div> </div>
</SettingsCategory> </SettingsCategory>
<SettingsCategory sectionId="saving" title={$t("settings.saving.title")}>
<Switcher big={true} description={$t("settings.saving.description")}>
{#each savingMethodOptions as value}
<SettingsButton
settingContext="save"
settingId="savingMethod"
settingValue={value}
>
{$t(`settings.saving.${value}`)}
</SettingsButton>
{/each}
</Switcher>
</SettingsCategory>
<SettingsCategory <SettingsCategory
sectionId="disable-metadata" sectionId="disable-metadata"
title={$t("settings.metadata.file")} title={$t("settings.metadata.file")}
@ -41,12 +55,3 @@
description={$t("settings.metadata.disable.description")} description={$t("settings.metadata.disable.description")}
/> />
</SettingsCategory> </SettingsCategory>
<SettingsCategory sectionId="saving" title={$t("settings.saving.method")}>
<SettingsToggle
settingContext="save"
settingId="downloadPopup"
title={$t("settings.saving.ask.title")}
description={$t("settings.saving.ask.description")}
/>
</SettingsCategory>