/* SETTINGS — source provider toggles, API server base URL, TMDB key, local data. */ (function () { 'use strict'; SR.app.initChrome(); const providerList = document.getElementById('providerList'); const providersStatus = document.getElementById('providersStatus'); const apiBaseInput = document.getElementById('apiBaseInput'); const connStatus = document.getElementById('connStatus'); const tmdbKeyInput = document.getElementById('tmdbKeyInput'); const tmdbStatus = document.getElementById('tmdbStatus'); const dataStatus = document.getElementById('dataStatus'); /* ---- nav --------------------------------------------------------------------- */ const navlinks = Array.from(document.querySelectorAll('.settings__navlink')); navlinks.forEach((link) => { link.addEventListener('click', (e) => { e.preventDefault(); const target = document.querySelector(link.getAttribute('href')); if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' }); navlinks.forEach((l) => l.classList.toggle('is-active', l === link)); history.replaceState(null, '', link.getAttribute('href')); }); }); /* ---- sources ------------------------------------------------------------------- */ let allProviders = []; let serverEnabled = []; const boxes = new Map(); // provider name -> checkbox function setStatus(el, message, kind) { el.textContent = message || ''; el.className = kind === 'ok' ? 'settings__status settings__status--ok' : kind === 'err' ? 'settings__status settings__status--err' : 'settings__status'; } function currentMap() { const map = {}; for (const [name, box] of boxes) map[name] = box.checked; return map; } function persist(map, message) { SR.config.setProviders(map); if (message) setStatus(providersStatus, message); } function renderProviders() { providerList.replaceChildren(); boxes.clear(); const overrides = SR.config.getProviders(); const enabled = SR.config.enabledProviders(allProviders, serverEnabled); for (const name of allProviders) { const checked = enabled.includes(name); const label = document.createElement('label'); label.className = 'provider'; const input = document.createElement('input'); input.type = 'checkbox'; input.checked = !!checked; const nameEl = document.createElement('span'); nameEl.className = 'provider__name'; nameEl.textContent = name; label.append(input, nameEl); input.addEventListener('change', () => persist(currentMap(), input.checked ? `${name} enabled` : `${name} disabled`)); boxes.set(name, input); providerList.appendChild(label); } const on = boxes.size ? Array.from(boxes.values()).filter((b) => b.checked).length : 0; const source = overrides ? 'your selection' : 'default sources'; let host; try { host = new URL(SR.config.getBase()).host; } catch (e) { host = SR.config.getBase(); } setStatus(providersStatus, `${on} of ${allProviders.length} enabled — ${source} · ${host}`); } function resetProviders(message) { SR.config.clearProviders(); renderProviders(); if (message) setStatus(providersStatus, message); } document.getElementById('allOn').addEventListener('click', () => { if (!boxes.size) return; for (const box of boxes.values()) box.checked = true; persist(currentMap(), 'All sources enabled'); }); document.getElementById('allOff').addEventListener('click', () => { if (!boxes.size) return; for (const box of boxes.values()) box.checked = false; persist(currentMap(), 'All sources disabled'); }); document.getElementById('providersReset').addEventListener('click', () => resetProviders('Using default sources')); async function initSources() { try { const data = await SR.api.providers(); allProviders = data.all || []; serverEnabled = data.enabled || []; renderProviders(); } catch (e) { setStatus(providersStatus, `Could not load the provider list: ${e.message}`, 'err'); } } /* ---- server ----------------------------------------------------------------------- */ apiBaseInput.value = SR.config.getBase(); async function testConnection() { try { const data = await SR.api.providers(); setStatus(connStatus, `Connected — ${data.all ? data.all.length : 0} provider(s) known.`, 'ok'); return true; } catch (e) { setStatus(connStatus, `Not reachable: ${e.message}`, 'err'); return false; } } document.getElementById('apiBaseSave').addEventListener('click', async () => { SR.config.setBase(apiBaseInput.value); apiBaseInput.value = SR.config.getBase(); SR.app.initChrome(); // refresh the footer label if (await testConnection()) SR.app.toast('API base URL saved'); }); document.getElementById('apiBaseReset').addEventListener('click', async () => { SR.config.clearBase(); apiBaseInput.value = SR.config.getBase(); SR.app.initChrome(); await testConnection(); }); /* ---- TMDB key ------------------------------------------------------------------- */ tmdbKeyInput.value = SR.config.getTmdbKey(); async function testTmdbKey(key) { setStatus(tmdbStatus, 'Testing TMDB key…'); try { await SR.api.tmdb('/search/movie', { query: 'The Matrix', page: 1 }, key); setStatus(tmdbStatus, 'TMDB key works — search, details and images load directly from TMDB.', 'ok'); } catch (e) { setStatus(tmdbStatus, e.message, 'err'); } } document.getElementById('tmdbKeySave').addEventListener('click', async () => { SR.config.setTmdbKey(tmdbKeyInput.value); tmdbKeyInput.value = SR.config.getTmdbKey(); await testTmdbKey(SR.config.getTmdbKey()); }); document.getElementById('tmdbKeyTest').addEventListener('click', async () => { await testTmdbKey(tmdbKeyInput.value.trim()); }); document.getElementById('tmdbKeyReset').addEventListener('click', async () => { SR.config.clearTmdbKey(); tmdbKeyInput.value = SR.config.getTmdbKey(); await testTmdbKey(SR.config.getTmdbKey()); }); /* ---- data ---------------------------------------------------------------------------- */ document.getElementById('clearHistory').addEventListener('click', () => { SR.storage.clear(); setStatus(dataStatus, 'Continue-watching history cleared.'); }); document.getElementById('resetProviders').addEventListener('click', () => { resetProviders(''); setStatus(dataStatus, 'Source toggles reset to default sources.'); }); initSources(); })();