import { pipe } from 'fp-ts/lib/function' import { matchW } from 'fp-ts/lib/TaskEither' import { ffetch } from '../lib/httpClient' import { prefersDarkMode } from '../utils' import { atomWithStorage } from 'jotai/utils' import { atom } from 'jotai' export const languages = [ 'catalan', 'chinese', 'english', 'french', 'german', 'italian', 'japanese', 'korean', 'polish', 'portuguese-br', 'russian', 'spanish', 'swedish', 'ukrainian', 'hungarian' ] as const export type Language = (typeof languages)[number] export type Theme = 'light' | 'dark' | 'system' export type ThemeNarrowed = 'light' | 'dark' export const accents = ['default', 'red'] as const export type Accent = (typeof accents)[number] export interface SettingsState { serverAddr: string serverPort: number language: Language theme: ThemeNarrowed accent: Accent cliArgs: string formatSelection: boolean fileRenaming: boolean autoFileExtension: boolean pathOverriding: boolean enableCustomArgs: boolean listView: boolean servedFromReverseProxy: boolean appTitle: string } export const languageState = atomWithStorage( 'language', localStorage.getItem('language') as Language || 'english' ) export const themeState = atomWithStorage( 'theme', localStorage.getItem('theme') as Theme || 'system' ) export const serverAddressState = atomWithStorage( 'server-addr', localStorage.getItem('server-addr') || window.location.hostname ) export const serverPortState = atomWithStorage( 'server-port', Number(localStorage.getItem('server-port')) || Number(window.location.port) ) export const latestCliArgumentsState = atomWithStorage( 'cli-args', localStorage.getItem('cli-args') || '--no-mtime' ) export const formatSelectionState = atomWithStorage( 'format-selection', localStorage.getItem('format-selection') === 'true' ) export const fileRenamingState = atomWithStorage( 'file-renaming', localStorage.getItem('file-renaming') === 'true' ) export const autoFileExtensionState = atomWithStorage( 'auto-file-extension', localStorage.getItem('auto-file-extension') === 'true' ) export const pathOverridingState = atomWithStorage( 'path-overriding', localStorage.getItem('path-overriding') === 'true' ) export const enableCustomArgsState = atomWithStorage( 'enable-custom-args', localStorage.getItem('enable-custom-args') === 'true' ) export const listViewState = atomWithStorage( 'listview', localStorage.getItem('listview') === 'true' ) export const servedFromReverseProxyState = atomWithStorage( 'reverseProxy', localStorage.getItem('reverseProxy') === 'true' || window.location.port == '' ) export const servedFromReverseProxySubDirState = atomWithStorage( 'reverseProxySubDir', localStorage.getItem('reverseProxySubDir') ?? '' ) export const appTitleState = atomWithStorage( 'appTitle', localStorage.getItem('appTitle') ?? 'yt-dlp Web UI' ) export const serverAddressAndPortState = atom((get) => { if (get(servedFromReverseProxySubDirState)) { return `${get(serverAddressState)}/${get(servedFromReverseProxySubDirState)}/` .replaceAll('"', '') // TODO: atomWithStorage put extra double quotes on strings } if (get(servedFromReverseProxyState)) { return `${get(serverAddressState)}` .replaceAll('"', '') } return `${get(serverAddressState)}:${get(serverPortState)}` .replaceAll('"', '') }) export const serverURL = atom((get) => `${window.location.protocol}//${get(serverAddressAndPortState)}` ) export const rpcWebSocketEndpoint = atom((get) => { const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:' return `${proto}//${get(serverAddressAndPortState)}/rpc/ws` }) export const rpcHTTPEndpoint = atom((get) => { const proto = window.location.protocol return `${proto}//${get(serverAddressAndPortState)}/rpc/http` }) export const serverSideCookiesState = atom>(async (get) => await pipe( ffetch>(`${get(serverURL)}/api/v1/cookies`), matchW( () => '', (r) => r.cookies ) )()) const themeSelector = atom((get) => { const theme = get(themeState) if ((theme === 'system' && prefersDarkMode()) || theme === 'dark') { return 'dark' } return 'light' }) export const accentState = atomWithStorage( 'accent-color', localStorage.getItem('accent-color') as Accent ?? 'default', ) export const settingsState = atom((get) => ({ serverAddr: get(serverAddressState), serverPort: get(serverPortState), language: get(languageState), theme: get(themeSelector), accent: get(accentState), cliArgs: get(latestCliArgumentsState), formatSelection: get(formatSelectionState), fileRenaming: get(fileRenamingState), autoFileExtension: get(autoFileExtensionState), pathOverriding: get(pathOverridingState), enableCustomArgs: get(enableCustomArgsState), listView: get(listViewState), servedFromReverseProxy: get(servedFromReverseProxyState), appTitle: get(appTitleState) }))