Show active worker in admin footer
This commit is contained in:
parent
ef4e1b48e7
commit
47f5a20a91
1 changed files with 35 additions and 2 deletions
37
new.php
37
new.php
|
|
@ -234,6 +234,33 @@ function input_dir_state($dir){
|
|||
$state = is_file($stateFile) ? json_decode((string)file_get_contents($stateFile), true) : [];
|
||||
return is_array($state) ? $state : [];
|
||||
}
|
||||
function active_worker_jobs($config){
|
||||
$jobs = [];
|
||||
foreach (input_dirs($config['uploads_dir']) as $dir) {
|
||||
$name = basename($dir);
|
||||
$state = input_dir_state($dir);
|
||||
$status = (string)($state['status'] ?? '');
|
||||
$locked = is_dir($dir . '/.movmaker-lock');
|
||||
if ($locked || $status === 'processing') {
|
||||
$started = '';
|
||||
if (is_file($dir . '/.movmaker-lock/started_at')) $started = trim((string)file_get_contents($dir . '/.movmaker-lock/started_at'));
|
||||
if ($started === '' && !empty($state)) $started = (string)($state['started_at'] ?? $state['updated_at'] ?? '');
|
||||
$jobs[] = ['name'=>$name,'status'=>$status ?: ($locked ? 'processing' : 'unknown'),'started_at'=>$started];
|
||||
}
|
||||
}
|
||||
return $jobs;
|
||||
}
|
||||
function format_job_age($startedAt){
|
||||
$ts = strtotime((string)$startedAt);
|
||||
if (!$ts) return '';
|
||||
$seconds = max(0, time() - $ts);
|
||||
$h = intdiv($seconds, 3600);
|
||||
$m = intdiv($seconds % 3600, 60);
|
||||
$s = $seconds % 60;
|
||||
if ($h > 0) return $h . 'h ' . $m . 'm';
|
||||
if ($m > 0) return $m . 'm ' . $s . 's';
|
||||
return $s . 's';
|
||||
}
|
||||
function input_dir_output($dir){
|
||||
$state = input_dir_state($dir);
|
||||
return basename((string)($state['output'] ?? ''));
|
||||
|
|
@ -415,6 +442,7 @@ $page = max(1, (int)($_GET['page'] ?? 1));
|
|||
$editName = $_GET['edit'] ?? '';
|
||||
$editDir = null; $editStatus = ''; $editRunning = false; $editData = ['title'=>'','date'=>'','place'=>'','description'=>'','captions'=>[],'video_audio'=>[]]; $editFiles = [];
|
||||
if ($editName !== '') { try { $editDir = safe_input_dir($config['uploads_dir'], $editName); $editStatus = input_dir_status($editDir); $editRunning = input_dir_running($editDir); if (!$editRunning) { $editData = read_data($editDir); $editFiles = media_sort_files($editDir, list_files($editDir)); } } catch (Throwable $e) { $err = $e->getMessage(); } }
|
||||
$runningJobs = active_worker_jobs($config);
|
||||
?>
|
||||
<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Admin - <?=h($config['site_name'])?></title><link rel="icon" type="image/png" href="assets/img/moto_travel.png"><link rel="stylesheet" href="style.css"></head><body>
|
||||
<header class="site-header admin-header"><div class="brand-wrap"><a class="header-logo" href="index.php" aria-label="MVLog home"><img src="assets/img/moto_travel.png" alt=""></a><a class="brand" href="index.php"><h1>MVLog Admin</h1><p>Bubulescu.Org</p></a></div></header>
|
||||
|
|
@ -605,10 +633,15 @@ document.querySelectorAll('.admin-switches input[type="checkbox"]').forEach(func
|
|||
box.hidden=false;
|
||||
box.innerHTML=jobs.map(fmt).join('');
|
||||
}catch(e){
|
||||
box.hidden=true;
|
||||
if(box.innerHTML.trim() !== '') box.hidden=false;
|
||||
}
|
||||
}
|
||||
updateJobs();
|
||||
setInterval(updateJobs,30000);
|
||||
})();
|
||||
</script></main><footer>Input dirs are saved under <code>in-dir/</code>.</footer><script>document.querySelectorAll('textarea[data-counter]').forEach(function(t){var c=document.getElementById(t.dataset.counter);function u(){c.textContent=t.value.length+' / '+t.maxLength+' characters';}t.addEventListener('input',u);u();});</script><footer class="site-footer admin-footer"><div class="admin-left"><nav class="tabs"><a class="<?= $tab==='new'?'active':'' ?>" href="new.php?tab=new">New</a><a class="<?= $tab==='edit'?'active':'' ?>" href="new.php?tab=edit">Edit</a><a class="<?= $tab==='videos'?'active':'' ?>" href="new.php?tab=videos">Videos</a></nav></div><div id="job-status" class="job-status" hidden></div><div class="admin-right"><a class="logout-link" href="logout.php">Log off</a></div></footer></body></html>
|
||||
</script></main>
|
||||
<footer>Input dirs are saved under <code>in-dir/</code>.</footer>
|
||||
<footer class="site-footer admin-footer"><div class="admin-left"><nav class="tabs"><a class="<?= $tab==='new'?'active':'' ?>" href="new.php?tab=new">New</a><a class="<?= $tab==='edit'?'active':'' ?>" href="new.php?tab=edit">Edit</a><a class="<?= $tab==='videos'?'active':'' ?>" href="new.php?tab=videos">Videos</a></nav></div><div id="job-status" class="job-status"<?= empty($runningJobs) ? ' hidden' : '' ?>><?php foreach($runningJobs as $job): ?><span class="job-dot"></span><span><?=h(str_replace('_', ' ', $job['name']))?></span><?php if(!empty($job['started_at'])): ?><span class="job-age">(<?=h(format_job_age($job['started_at']))?>)</span><?php endif; ?><?php endforeach; ?></div><div class="admin-right"><a class="logout-link" href="logout.php">Log off</a></div></footer>
|
||||
<script>document.querySelectorAll('textarea[data-counter]').forEach(function(t){var c=document.getElementById(t.dataset.counter);function u(){c.textContent=t.value.length+' / '+t.maxLength+' characters';}t.addEventListener('input',u);u();});</script>
|
||||
<script>(function(){const box=document.getElementById('job-status');if(!box)return;function fmt(job){const name=(job.name||'job').replace(/_/g,' ');const started=job.started_at ? new Date(job.started_at) : null;const ageText=started && !Number.isNaN(started.getTime()) ? ' <span class="job-age">(' + formatAge(started) + ')</span>' : '';return '<span class="job-dot"></span><span>'+name+'</span>'+ageText;}function formatAge(started){const seconds=Math.max(0,Math.floor((Date.now()-started.getTime())/1000));const h=Math.floor(seconds/3600);const m=Math.floor((seconds%3600)/60);const s=seconds%60;if(h>0) return h+'h '+m+'m';if(m>0) return m+'m '+s+'s';return s+'s';}function syncEditButtons(runningJobs){document.querySelectorAll('.admin-video-row[data-job]').forEach(function(row){const job=row.dataset.job || '';const edit=row.querySelector('[data-edit-action="1"]');if(!edit) return;const running=runningJobs.has(job);if(edit.tagName==='A'){if(running){if(!edit.dataset.editHref) edit.dataset.editHref = edit.getAttribute('href') || '';edit.removeAttribute('href');edit.classList.add('disabled');edit.setAttribute('aria-disabled','true');edit.title='Rendering now';}else{const href=edit.dataset.editHref || ('?edit=' + encodeURIComponent(job));edit.setAttribute('href', href);edit.classList.remove('disabled');edit.removeAttribute('aria-disabled');edit.title='Edit';}}else{edit.classList.toggle('disabled', running);edit.title=running ? 'Rendering now' : '';}});}async function updateJobs(){try{const r=await fetch('job_status.php',{cache:'no-store'});if(!r.ok) throw new Error('status failed');const data=await r.json();const jobs=(data.jobs||[]).filter(function(job){ return job && job.name; });const runningJobs=new Set(jobs.map(function(job){ return String(job.name); }));syncEditButtons(runningJobs);if(!jobs.length){box.hidden=true;box.innerHTML='';return;}box.hidden=false;box.innerHTML=jobs.map(fmt).join('');}catch(e){if(box.innerHTML.trim()!=='') box.hidden=false;}}updateJobs();setInterval(updateJobs,30000);})();</script>
|
||||
</body></html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue