()
| 144 | }; |
| 145 | |
| 146 | export const loadDanmuPreferences = (): { enabled: boolean; settings: DanmuUserSettings } | null => { |
| 147 | if (typeof window === 'undefined' || !window.localStorage) { |
| 148 | return null; |
| 149 | } |
| 150 | try { |
| 151 | const raw = window.localStorage.getItem(DANMU_PREFERENCES_STORAGE_KEY); |
| 152 | if (!raw) { |
| 153 | return null; |
| 154 | } |
| 155 | const parsed = JSON.parse(raw); |
| 156 | if (!parsed || typeof parsed !== 'object') { |
| 157 | return null; |
| 158 | } |
| 159 | const settings = parsed.settings ?? {}; |
| 160 | return { |
| 161 | enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : true, |
| 162 | settings: { |
| 163 | color: typeof settings.color === 'string' ? settings.color : '#ffffff', |
| 164 | strokeColor: typeof settings.strokeColor === 'string' ? settings.strokeColor : '#444444', |
| 165 | fontSize: typeof settings.fontSize === 'string' ? settings.fontSize : '20px', |
| 166 | duration: Number.isFinite(settings.duration) ? settings.duration : 10000, |
| 167 | area: Number.isFinite(settings.area) ? sanitizeDanmuArea(settings.area) : 0.5, |
| 168 | mode: settings.mode === 'top' || settings.mode === 'bottom' ? settings.mode : 'scroll', |
| 169 | opacity: Number.isFinite(settings.opacity) ? sanitizeDanmuOpacity(settings.opacity) : 1, |
| 170 | }, |
| 171 | }; |
| 172 | } catch (error) { |
| 173 | console.warn('[DanmuPreferences] Failed to load preferences:', error); |
| 174 | return null; |
| 175 | } |
| 176 | }; |
| 177 | |
| 178 | export const persistDanmuPreferences = (payload: { enabled: boolean; settings: DanmuUserSettings }) => { |
| 179 | if (typeof window === 'undefined' || !window.localStorage) { |
no test coverage detected