f580d88a14
gates / gates (push) Successful in 45s
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
75 lines
5.2 KiB
HTML
75 lines
5.2 KiB
HTML
{{/*
|
|
media_notice (v0.313.0, `09` §3 decisions 238/239/245) — the media drive notice: a drive was added, removed or came back,
|
|
so the media apps must restart to see it; „restart now" (after a stream check) or „later" (tonight 03:30); per drive
|
|
„apps restarted since this change: yes/no"; and the result of the drive wiring. Rendered empty and filled from
|
|
GET /api/storage/media/status, so every page that includes it shows the same truth. Hidden when there is nothing to say.
|
|
*/}}
|
|
{{define "media_notice"}}
|
|
<div id="media-notice" class="settings-card media-notice" hidden>
|
|
<h3>{{T "media.notice_title"}}</h3>
|
|
<p class="settings-card-desc">{{T "media.notice_body"}}</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">{{T "media.restart_now"}}</button>
|
|
<button type="button" class="btn btn-sm btn-outline" id="media-restart-later">{{T "media.restart_later"}}</button>
|
|
</div>
|
|
<div id="media-notice-out"></div>
|
|
<div id="media-wiring" hidden>
|
|
<h4>{{T "media.wiring_title"}}</h4>
|
|
<ul id="media-wiring-list" class="media-notice-list"></ul>
|
|
<p id="media-wiring-hint" class="form-hint" hidden>{{T "media.jellyfin_key_hint"}}</p>
|
|
<button type="button" class="btn btn-sm btn-outline" id="media-wire-now">{{T "media.wire_now"}}</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:"{{T "media.change_added"}}",removed:"{{T "media.change_removed"}}",returned:"{{T "media.change_returned"}}",
|
|
yes:"{{T "media.restarted_yes"}}",no:"{{T "media.restarted_no"}}",apps:"{{T "media.apps"}}",stale:"{{T "media.stale"}}",
|
|
later:"{{T "media.later_at"}}",streams:"{{T "media.streams_playing"}}",done:"{{T "media.restart_done"}}",
|
|
err:"{{T "media.error"}}",household:"{{T "media.state_household"}}"};
|
|
function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[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>
|
|
{{end}}
|