From 5a630c2320b8d146efed3e88b38aec6dd858fb21 Mon Sep 17 00:00:00 2001
From: dumbmoron <log@riseup.net>
Date: Sat, 13 Jul 2024 20:37:38 +0000
Subject: [PATCH] web/migrate: set up migration from old settings format

---
 web/src/lib/settings/migrate.ts | 115 ++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 web/src/lib/settings/migrate.ts

diff --git a/web/src/lib/settings/migrate.ts b/web/src/lib/settings/migrate.ts
new file mode 100644
index 00000000..64c9ae53
--- /dev/null
+++ b/web/src/lib/settings/migrate.ts
@@ -0,0 +1,115 @@
+import type { RecursivePartial } from "$lib/types/generic";
+import type { CobaltSettings } from "$lib/types/settings";
+import defaultSettings from "./defaults";
+
+const oldSwitcherValues = {
+    theme: ['auto', 'light', 'dark'],
+    vCodec: ['h264', 'av1', 'vp9'],
+    vQuality: ['720', 'max', '2160', '1440', '1080', '480', '360', '240', '144'],
+    aFormat: ['mp3', 'best', 'ogg', 'wav', 'opus'],
+    filenamePattern: ['classic', 'pretty', 'basic', 'nerdy']
+} as const;
+
+const oldCheckboxes = [
+    'audioMode',
+    'downloadPopup',
+    'fullTikTokAudio',
+    'muteAudio',
+    'reduceTransparency',
+    'disableAnimations',
+    'disableMetadata',
+    'twitterGif',
+    'plausible_ignore',
+    'ytDub',
+    'tiktokH265'
+] as const;
+
+type LegacySwitchers = keyof typeof oldSwitcherValues;
+type LegacyCheckboxes = typeof oldCheckboxes[number];
+
+const _get = (name: LegacyCheckboxes | LegacySwitchers) => {
+    const value = localStorage.getItem(name);
+    if (value !== null) {
+        return value;
+    }
+}
+
+const getBool = (name: LegacyCheckboxes) => {
+    const value = _get(name);
+
+    if (value !== undefined) {
+        return value === 'true';
+    }
+}
+
+const getLiteral = <T extends LegacySwitchers>(name: T) => {
+    const value = _get(name);
+    if (value === undefined) {
+        return;
+    }
+
+    const values = oldSwitcherValues[name] as readonly string[];
+    if (values.includes(value)) {
+        type SwitcherOptions = typeof oldSwitcherValues[T][number];
+        return value as SwitcherOptions;
+    }
+}
+
+const getDownloadMode = () => {
+    if (getBool('muteAudio')) {
+        return 'mute';
+    }
+
+    if (getBool('audioMode')) {
+        return 'audio';
+    }
+
+    return 'auto';
+}
+
+const cleanup = () => {
+    for (const key of Object.keys(localStorage)) {
+        // plausible script needs this value, so we keep it if migrating
+        if (key !== 'plausible_ignore') {
+            localStorage.removeItem(key);
+        }
+    }
+}
+
+export const migrateOldSettings = () => {
+    if (getLiteral('vCodec') === undefined) {
+        /* on the old frontend, preferences such as "vCodec" are set right
+         * when you open it. so, if this preference does not exist, we can
+         * assume that the user never used the old frontend, and abort the
+         * migration early. */
+        return;
+    }
+
+    const migrated: RecursivePartial<CobaltSettings> = {
+        schemaVersion: defaultSettings.schemaVersion,
+        appearance: {
+            theme: getLiteral('theme'),
+            reduceTransparency: getBool('reduceTransparency'),
+            reduceMotion: getBool('disableAnimations'),
+        },
+        privacy: {
+            disableAnalytics: getBool('plausible_ignore')
+        },
+        save: {
+            youtubeVideoCodec: getLiteral('vCodec'),
+            videoQuality: getLiteral('vQuality'),
+            audioFormat: getLiteral('aFormat'),
+            downloadMode: getDownloadMode(),
+            filenameStyle: getLiteral('filenamePattern'),
+            tiktokFullAudio: getBool('fullTikTokAudio'),
+            tiktokH265: getBool('tiktokH265'),
+            downloadPopup: getBool('downloadPopup'),
+            disableMetadata: getBool('disableMetadata'),
+            twitterGif: getBool('twitterGif'),
+            youtubeDubBrowserLang: getBool('ytDub'),
+        }
+    };
+
+    cleanup();
+    return migrated;
+}