import { createEffect, createMemo, createSignal, For, Index, Match, onCleanup, onMount, type Setter, Switch, } from 'solid-js'; import * as z from 'zod'; import { type ProviderName, providerNames, ProviderNameSchema, type ProviderState, } from '../../providers'; import { currentLyrics, lyricsStore, setLyricsStore } from '../store'; import { _ytAPI } from '../index'; import { config } from '../renderer'; import type { YtIcons } from '@/types/icons'; import type { PlayerAPIEvents } from '@/types/player-api-events'; const LocalStorageSchema = z.object({ provider: ProviderNameSchema, }); export const providerIdx = createMemo(() => providerNames.indexOf(lyricsStore.provider), ); const shouldSwitchProvider = (providerData: ProviderState) => { if (providerData.state === 'error') return true; if (providerData.state === 'fetching') return true; return ( providerData.state === 'done' && !providerData.data?.lines && !providerData.data?.lyrics ); }; const providerBias = (p: ProviderName) => (lyricsStore.lyrics[p].state === 'done' ? 1 : -1) + (lyricsStore.lyrics[p].data?.lines?.length ? 2 : -1) + (lyricsStore.lyrics[p].data?.lines?.length && p === 'YTMusic' ? 1 : 0) + (lyricsStore.lyrics[p].data?.lyrics ? 1 : -1); const pickBestProvider = () => { const preferred = config()?.preferredProvider; if (preferred) { const data = lyricsStore.lyrics[preferred].data; if (Array.isArray(data?.lines) || data?.lyrics) { return { provider: preferred, force: true }; } } const providers = Array.from(providerNames); providers.sort((a, b) => providerBias(b) - providerBias(a)); return { provider: providers[0], force: false }; }; const [hasManuallySwitchedProvider, setHasManuallySwitchedProvider] = createSignal(false); export const LyricsPicker = (props: { setStickRef: Setter; }) => { const [videoId, setVideoId] = createSignal(null); const [starredProvider, setStarredProvider] = createSignal(null); createEffect(() => { const id = videoId(); if (id === null) { setStarredProvider(null); return; } const key = `ytmd-sl-starred-${id}`; const value = localStorage.getItem(key); if (!value) { setStarredProvider(null); return; } const parseResult = LocalStorageSchema.safeParse(JSON.parse(value)); if (parseResult.success) { setLyricsStore('provider', parseResult.data.provider); setStarredProvider(parseResult.data.provider); } else { setStarredProvider(null); } }); const toggleStar = () => { const id = videoId(); if (id === null) return; const key = `ytmd-sl-starred-${id}`; setStarredProvider((starredProvider) => { if (lyricsStore.provider === starredProvider) { localStorage.removeItem(key); return null; } const provider = lyricsStore.provider; localStorage.setItem(key, JSON.stringify({ provider })); return provider; }); }; const videoDataChangeHandler = ( name: string, { videoId }: PlayerAPIEvents['videodatachange']['value'], ) => { setVideoId(videoId); if (name !== 'dataloaded') return; setHasManuallySwitchedProvider(false); }; // prettier-ignore { onMount(() => _ytAPI?.addEventListener('videodatachange', videoDataChangeHandler)); onCleanup(() => _ytAPI?.removeEventListener('videodatachange', videoDataChangeHandler)); } createEffect(() => { if (!hasManuallySwitchedProvider()) { const starred = starredProvider(); if (starred !== null) { setLyricsStore('provider', starred); return; } const allProvidersFailed = providerNames.every((p) => shouldSwitchProvider(lyricsStore.lyrics[p]), ); if (allProvidersFailed) return; const { provider, force } = pickBestProvider(); if ( force || providerBias(lyricsStore.provider) < providerBias(provider) ) { setLyricsStore('provider', provider); } } }); const next = () => { setHasManuallySwitchedProvider(true); setLyricsStore('provider', (prevProvider) => { const idx = providerNames.indexOf(prevProvider); return providerNames[(idx + 1) % providerNames.length]; }); }; const previous = () => { setHasManuallySwitchedProvider(true); setLyricsStore('provider', (prevProvider) => { const idx = providerNames.indexOf(prevProvider); return providerNames[ (idx + providerNames.length - 1) % providerNames.length ]; }); }; const chevronLeft: YtIcons = 'yt-icons:chevron_left'; const chevronRight: YtIcons = 'yt-icons:chevron_right'; const successIcon: YtIcons = 'yt-icons:check-circle'; const errorIcon: YtIcons = 'yt-icons:error'; const notFoundIcon: YtIcons = 'yt-icons:warning'; return (
    {(_, idx) => (
  • setLyricsStore('provider', providerNames[idx()])} style={{ background: idx() === providerIdx() ? 'white' : 'black', }} /> )}
); };