web: implement settings core
this was a torture
This commit is contained in:
parent
21e03a407c
commit
009a2cc863
6 changed files with 139 additions and 2 deletions
12
web/package-lock.json
generated
12
web/package-lock.json
generated
|
@ -11,7 +11,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/noto-sans-mono": "^5.0.20",
|
"@fontsource-variable/noto-sans-mono": "^5.0.20",
|
||||||
"@fontsource/ibm-plex-mono": "^5.0.13",
|
"@fontsource/ibm-plex-mono": "^5.0.13",
|
||||||
"@tabler/icons-svelte": "^3.6.0"
|
"@tabler/icons-svelte": "^3.6.0",
|
||||||
|
"ts-deepmerge": "^7.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.5.0",
|
"@eslint/js": "^9.5.0",
|
||||||
|
@ -3048,6 +3049,15 @@
|
||||||
"typescript": ">=4.2.0"
|
"typescript": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-deepmerge": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-WZ/iAJrKDhdINv1WG6KZIGHrZDar6VfhftG1QJFpVbOYZMYJLJOvZOo1amictRXVdBXZIgBHKswMTXzElngprA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.6.3",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/noto-sans-mono": "^5.0.20",
|
"@fontsource-variable/noto-sans-mono": "^5.0.20",
|
||||||
"@fontsource/ibm-plex-mono": "^5.0.13",
|
"@fontsource/ibm-plex-mono": "^5.0.13",
|
||||||
"@tabler/icons-svelte": "^3.6.0"
|
"@tabler/icons-svelte": "^3.6.0",
|
||||||
|
"ts-deepmerge": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
42
web/src/lib/settings.ts
Normal file
42
web/src/lib/settings.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { readable, type Updater } from 'svelte/store';
|
||||||
|
import { merge } from 'ts-deepmerge';
|
||||||
|
|
||||||
|
import type { RecursivePartial } from './types/generic';
|
||||||
|
import type { CobaltSettings } from './types/settings';
|
||||||
|
|
||||||
|
import defaultSettings from "$lib/settings/defaults";
|
||||||
|
|
||||||
|
const writeToStorage = (settings: CobaltSettings) => {
|
||||||
|
localStorage.setItem(
|
||||||
|
"settings",
|
||||||
|
JSON.stringify(settings)
|
||||||
|
);
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadFromStorage = () => {
|
||||||
|
const settings = localStorage.getItem('settings');
|
||||||
|
if (!settings) {
|
||||||
|
return writeToStorage(defaultSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(settings) as CobaltSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
let update: (_: Updater<CobaltSettings>) => void;
|
||||||
|
|
||||||
|
export default readable<CobaltSettings>(
|
||||||
|
loadFromStorage(),
|
||||||
|
(_, _update) => { update = _update }
|
||||||
|
);
|
||||||
|
|
||||||
|
// update settings from outside
|
||||||
|
export function updateSetting(settings: RecursivePartial<CobaltSettings>) {
|
||||||
|
update((current) => {
|
||||||
|
// deep merge partial type into full CobaltSettings type
|
||||||
|
current = merge(current, settings) as CobaltSettings;
|
||||||
|
|
||||||
|
return writeToStorage(current);
|
||||||
|
});
|
||||||
|
}
|
35
web/src/lib/settings/defaults.ts
Normal file
35
web/src/lib/settings/defaults.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import type { CobaltSettings } from "$lib/types/settings";
|
||||||
|
|
||||||
|
const defaultSettings: CobaltSettings = {
|
||||||
|
schemaVersion: 1,
|
||||||
|
accessibility: {
|
||||||
|
reduceAnimations: false,
|
||||||
|
reduceTransparency: false
|
||||||
|
},
|
||||||
|
appearance: {
|
||||||
|
theme: "auto"
|
||||||
|
},
|
||||||
|
general: {
|
||||||
|
customProcessingEndpoint: "",
|
||||||
|
seenOnboarding: false,
|
||||||
|
seenSafetyWarning: false
|
||||||
|
},
|
||||||
|
save: {
|
||||||
|
audioFormat: "mp3",
|
||||||
|
disableMetadata: false,
|
||||||
|
downloadMode: "auto",
|
||||||
|
downloadPopup: true,
|
||||||
|
filenameStyle: "classic",
|
||||||
|
tiktokH265: false,
|
||||||
|
tiktokFullAudio: false,
|
||||||
|
twitterGif: false,
|
||||||
|
videoQuality: "720",
|
||||||
|
youtubeVideoCodec: "h264",
|
||||||
|
youtubeDubBrowserLang: false
|
||||||
|
},
|
||||||
|
privacy: {
|
||||||
|
trafficAnalytics: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defaultSettings;
|
8
web/src/lib/types/generic.ts
Normal file
8
web/src/lib/types/generic.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// more readable version of recursive partial taken from stackoverflow:
|
||||||
|
// https://stackoverflow.com/a/51365037
|
||||||
|
export type RecursivePartial<Type> = {
|
||||||
|
[Key in keyof Type]?:
|
||||||
|
Type[Key] extends (infer ElementType)[] ? RecursivePartial<ElementType>[] :
|
||||||
|
Type[Key] extends object | undefined ? RecursivePartial<Type[Key]> :
|
||||||
|
Type[Key];
|
||||||
|
};
|
41
web/src/lib/types/settings.ts
Normal file
41
web/src/lib/types/settings.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
type CobaltSettingsAccessibility = {
|
||||||
|
reduceAnimations: boolean,
|
||||||
|
reduceTransparency: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type CobaltSettingsAppearance = {
|
||||||
|
theme: "auto" | "light" | "dark",
|
||||||
|
};
|
||||||
|
|
||||||
|
type CobaltSettingsGeneral = {
|
||||||
|
customProcessingEndpoint: string,
|
||||||
|
seenOnboarding: boolean,
|
||||||
|
seenSafetyWarning: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type CobaltSettingsSave = {
|
||||||
|
audioFormat: "best" | "mp3" | "ogg" | "wav" | "opus",
|
||||||
|
disableMetadata: boolean,
|
||||||
|
downloadMode: "auto" | "audio" | "mute",
|
||||||
|
downloadPopup: boolean,
|
||||||
|
filenameStyle: "classic" | "basic" | "pretty" | "nerdy",
|
||||||
|
tiktokH265: boolean,
|
||||||
|
tiktokFullAudio: boolean,
|
||||||
|
twitterGif: boolean,
|
||||||
|
videoQuality: "max" | "2160" | "1440" | "1080" | "720" | "360" | "240" | "144",
|
||||||
|
youtubeVideoCodec: "h264" | "av1" | "vp9",
|
||||||
|
youtubeDubBrowserLang: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type CobaltSettingsPrivacy = {
|
||||||
|
trafficAnalytics: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CobaltSettings = {
|
||||||
|
schemaVersion: number,
|
||||||
|
accessibility: CobaltSettingsAccessibility,
|
||||||
|
appearance: CobaltSettingsAppearance,
|
||||||
|
general: CobaltSettingsGeneral,
|
||||||
|
save: CobaltSettingsSave,
|
||||||
|
privacy: CobaltSettingsPrivacy,
|
||||||
|
};
|
Loading…
Reference in a new issue