Media build part 2 (unreleased): drive wiring in every app (R-1024/R-1037), old-install repair (R-1047), drive events notice + real restart now/later + stream check, file browser lets go of dead/removed drives and recreates on return (R-1038), safe removal keeps the drive (R-1044), Plex claim on the running server + probe accept (R-1028/R-1045)
gates / gates (push) Successful in 45s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-15 09:54:49 +02:00
parent 78c894234c
commit f580d88a14
46 changed files with 3700 additions and 8 deletions
@@ -176,6 +176,74 @@
<h2>Tárhely — Meghajtók</h2>
</div>
<div id="media-notice" class="settings-card media-notice" hidden>
<h3>A médiaalkalmazásoknak újra kell indulniuk</h3>
<p class="settings-card-desc">Egy meghajtó megváltozott. A médiaalkalmazások csak újraindítás után látják a változást.</p>
<ul id="media-notice-drives" class="media-notice-list"></ul>
<p id="media-notice-apps" class="form-hint"></p>
<p id="media-notice-stale" class="form-hint" hidden></p>
<p id="media-notice-later" class="form-hint" hidden></p>
<div class="media-notice-actions">
<button type="button" class="btn btn-sm btn-primary" id="media-restart-now">Újraindítás most</button>
<button type="button" class="btn btn-sm btn-outline" id="media-restart-later">Később (ma éjjel 3:30)</button>
</div>
<div id="media-notice-out"></div>
<div id="media-wiring" hidden>
<h4>Meghajtók bekötése az alkalmazásokba</h4>
<ul id="media-wiring-list" class="media-notice-list"></ul>
<p id="media-wiring-hint" class="form-hint" hidden>Jellyfin: Vezérlőpult → API-kulcsok → +, a kulcs neve: felhom. Utána nyomd meg a „Bekötés most” gombot.</p>
<button type="button" class="btn btn-sm btn-outline" id="media-wire-now">Bekötés most</button>
</div>
</div>
<script>
(function(){
var box=document.getElementById('media-notice'); if(!box) return;
var csrf=(document.querySelector('meta[name="csrf-token"]')||{}).content||'';
var L={added:"hozzáadva",removed:"eltávolítva",returned:"visszatért",
yes:"az alkalmazások azóta újraindultak: igen",no:"az alkalmazások azóta újraindultak: nem",apps:"Érintett alkalmazások:",stale:"Még egy halott meghajtót tart:",
later:"Ütemezve:",streams:"Most is megy egy lejátszás. Az újraindítás megszakítja. Biztosan újraindítod?",done:"Újraindítva. A meghajtók bekötése egy-két perc múlva kész.",
err:"Hiba:",household:"egy lépés kell tőled"};
function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c];});}
function li(t){var e=document.createElement('li'); e.textContent=t; return e;}
async function load(){
try{
var r=await fetch('/api/storage/media/status',{credentials:'same-origin'}); var j=await r.json(); if(!j.ok||!j.data) return;
var d=j.data; if(!d.apps||!d.apps.length) return;
var ul=document.getElementById('media-notice-drives'); ul.innerHTML='';
(d.drives||[]).forEach(function(x){ ul.appendChild(li(x.label+' — '+(L[x.change]||x.change)+' — '+(x.restarted?L.yes:L.no))); });
document.getElementById('media-notice-apps').textContent=L.apps+' '+d.apps.join(', ');
var st=document.getElementById('media-notice-stale'); if(d.stale&&d.stale.length){st.textContent=L.stale+' '+d.stale.join(', '); st.hidden=false;}
var la=document.getElementById('media-notice-later'); if(d.later_at){la.textContent=L.later+' '+d.later_at; la.hidden=false;}
if(d.wiring&&d.wiring.length){
var wl=document.getElementById('media-wiring-list'); wl.innerHTML=''; var hh=false;
d.wiring.forEach(function(x){ if(x.app==='folders') return; var t=x.app+': '+(x.state==='household'?L.household:x.state)+(x.detail&&x.state==='error'?' ('+x.detail+')':''); wl.appendChild(li(t)); if(x.state==='household'&&x.app==='jellyfin') hh=true; });
document.getElementById('media-wiring-hint').hidden=!hh; document.getElementById('media-wiring').hidden=false;
}
var show=d.pending||!!(d.wiring&&d.wiring.some(function(x){return x.state==='household'||x.state==='error';}));
document.querySelector('.media-notice-actions').hidden=!d.pending;
box.hidden=!show;
}catch(e){}
}
async function post(url,body){
var r=await fetch(url,{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/json','X-CSRF-Token':csrf},body:JSON.stringify(body||{})});
var j={}; try{j=await r.json();}catch(e){} return {status:r.status,j:j};
}
var out=document.getElementById('media-notice-out');
async function restart(force){
out.innerHTML='';
var res=await post('/api/storage/media/restart',{when:'now',force:!!force});
if(res.status===409){ felhomConfirm(document.getElementById('media-restart-now'), L.streams, function(){ restart(true); }); return; }
out.innerHTML=res.j.ok?'<div class="alert alert-info">'+esc(L.done)+'</div>':'<div class="alert alert-error">'+esc(L.err)+' '+esc(res.j.error||((res.j.data||{}).failed||[]).join(', '))+'</div>';
load();
}
document.getElementById('media-restart-now').addEventListener('click',function(){restart(false);});
document.getElementById('media-restart-later').addEventListener('click',async function(){ await post('/api/storage/media/restart',{when:'later'}); load(); });
document.getElementById('media-wire-now').addEventListener('click',async function(){ await post('/api/storage/media/wire',{}); load(); });
load();
})();
</script>
<div class="settings-card">
<h3>Adattárolók</h3>