diff --git a/vidflow.html b/vidflow.html
index 3e991aa..d61ecb5 100644
--- a/vidflow.html
+++ b/vidflow.html
@@ -179,6 +179,22 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
/* URL form */
.url-hint{font-size:11px;color:var(--dim);margin-bottom:10px;line-height:1.6;letter-spacing:.3px}
+.set-section{margin-bottom:20px}
+.set-hd{font-size:10px;letter-spacing:2px;text-transform:uppercase;color:var(--dim);font-weight:700;margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--border)}
+.set-row{display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.04)}
+.set-lbl{font-size:13px;font-weight:600;letter-spacing:.3px}
+.set-sub{font-size:10px;color:var(--dim);margin-top:2px;letter-spacing:.3px}
+.tog{width:36px;height:20px;background:rgba(255,255,255,.1);border-radius:10px;position:relative;cursor:pointer;transition:.2s;flex-shrink:0;border:none}
+.tog.on{background:var(--accent2)}
+.tog::after{content:'';position:absolute;width:14px;height:14px;background:#fff;border-radius:50%;top:3px;left:3px;transition:.2s}
+.tog.on::after{left:19px}
+.set-vol{display:flex;align-items:center;gap:8px;padding:8px 0}
+.set-vol input[type=range]{flex:1;-webkit-appearance:none;height:3px;background:rgba(255,255,255,.15);border-radius:2px;outline:none}
+.set-vol input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--accent2);border-radius:50%;cursor:pointer}
+.set-vol-lbl{font-size:11px;color:var(--dim);min-width:32px;text-align:right}
+.set-key-row{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid rgba(255,255,255,.03)}
+.set-key{font-family:var(--font-b);font-size:11px;color:var(--dim);letter-spacing:.3px}
+.set-kbd{font-family:monospace;font-size:11px;color:var(--accent2);background:rgba(0,212,255,.08);padding:1px 6px;border-radius:3px}
/* Empty state */
.empty{text-align:center;padding:36px 16px;color:var(--dim)}
@@ -365,7 +381,8 @@ body.idle .gt,body.idle .gb,body.idle .gr,body.idle .gl{opacity:0;transition:opa
MY LIST
SEARCH
-
ADD URL
+
ADD
+
SETTINGS
@@ -413,6 +430,8 @@ function sizePW(){
function onPReady(){
A.ready=true; hideLoad(); sizePW();
+ const _vol=parseInt(localStorage.getItem('vf_volume')||'100');
+ try{ A.player.setVolume(_vol); }catch(e){}
// Popup: check for video transferred from main window
if(window.opener){
try{
@@ -630,6 +649,7 @@ function renderTab(tab){
if(tab==='channels') renderChTab();
else if(tab==='search') renderSearchTab();
else if(tab==='add') renderAddTab();
+ else if(tab==='settings') renderSettingsTab();
}
function renderChTab(){
@@ -708,6 +728,74 @@ function renderAddTab(){
setTimeout(()=>inp.focus(),50);
}
+function renderSettingsTab(){
+ const b=qs('#sb-body');
+ const shuf=A.shuffled;
+ const vol=parseInt(localStorage.getItem('vf_volume')||'100');
+ b.innerHTML=`
+
+
API KEY
+
+
YouTube Data API v3 Key
+ ${A.apiKey?`
Current key: …${esc(A.apiKey.slice(-8))}
`:''}
+
+
+
+
+ ${A.apiKey?`
`:''}
+
+
+
+
PLAYBACK
+
+
Shuffle
Play channels in random order
+
+
+
+
+
VOLUME
+
+
+ ${vol}%
+
+
+
+
KEYBOARD SHORTCUTS
+
Play / PauseSpace
+
Prev / Next video← →
+
Volume↑ ↓
+
Channel up / down+ -
+
ShuffleS
+
Channels panelC
+
Pop-out playerP
+
FullscreenF
+
Close panelEsc
+
`;
+ const keyIn=qs('#set-key-in');
+ const doSaveKey=()=>{
+ const k=keyIn.value.trim(); if(!k){ toast('Enter a key'); return; }
+ A.apiKey=k; save(); toast('Key saved'); renderSettingsTab();
+ };
+ qs('#set-key-save').onclick=doSaveKey;
+ keyIn.onkeydown=e=>{ if(e.key==='Enter') doSaveKey(); };
+ const resetEl=qs('#set-key-reset');
+ if(resetEl) resetEl.onclick=()=>{ if(confirm('Clear API key and restart?')){ localStorage.removeItem('vf_key'); location.reload(); } };
+ qs('#tog-shuf').onclick=()=>{
+ A.shuffled=!A.shuffled;
+ qs('#b-shuf').classList.toggle('act',A.shuffled);
+ try{ A.player?.setShuffle?.(A.shuffled); }catch(e){}
+ localStorage.setItem('vf_shuffle',A.shuffled);
+ qs('#tog-shuf').classList.toggle('on',A.shuffled);
+ };
+ const volIn=qs('#set-vol-in'), volVal=qs('#set-vol-val');
+ volIn.oninput=()=>{
+ const v=parseInt(volIn.value);
+ volVal.textContent=v+'%';
+ try{ A.player?.setVolume?.(v); }catch(e){}
+ localStorage.setItem('vf_volume',v);
+ };
+}
+
// ── NCO onboarding ──
function initNCO(){
const demo=A.demo&&!A.apiKey;
@@ -805,6 +893,7 @@ function loadState(){
A.apiKey=localStorage.getItem('vf_key')||'';
try{ A.channels=JSON.parse(localStorage.getItem('vf_ch')||'[]'); }catch(e){ A.channels=[]; }
A.cur=parseInt(localStorage.getItem('vf_cur')||'-1');
+ A.shuffled = localStorage.getItem('vf_shuffle') !== 'false';
if(A.cur>=A.channels.length) A.cur=A.channels.length>0?0:-1;
}
@@ -868,9 +957,7 @@ function wireControls(){
if(!document.fullscreenElement) document.documentElement.requestFullscreen?.().catch(()=>{});
else document.exitFullscreen?.();
};
- qs('#cfg-btn').onclick=()=>{
- if(confirm('Change API key? App will reload.')){ localStorage.removeItem('vf_key'); location.reload(); }
- };
+ qs('#cfg-btn').onclick=()=>{ openSB(); renderTab('settings'); };
qs('#pb-wrap').onclick=e=>{
try{
if(!A.player?.getDuration) return;