diff --git a/admin.php b/admin.php
index 7611602..526f82b 100644
--- a/admin.php
+++ b/admin.php
@@ -887,11 +887,10 @@ function input_dir_status($dir){
return in_array($status, ['processing', 'stale', 'error'], true) ? $status : '';
}
function input_dir_running($dir){
- $stateFile = $dir . '/.movmaker-state.json';
- $lockDir = $dir . '/.movmaker-lock';
- $state = is_file($stateFile) ? json_decode((string)file_get_contents($stateFile), true) : [];
- $status = is_array($state) ? (string)($state['status'] ?? '') : '';
- return is_dir($lockDir) || $status === 'processing';
+ // Only the lock directory means this row is actively being rendered.
+ // A stale "processing" value in .movmaker-state.json must not disable
+ // Edit/Describe for unrelated rows while another job is running.
+ return is_dir($dir . '/.movmaker-lock');
}
function input_dir_enabled($dir){ return is_file($dir . '/.movmaker-enabled'); }
function set_input_dir_enabled($dir, $enabled){
@@ -1041,7 +1040,7 @@ function active_worker_jobs($config){
$articleId = (string)($state['article_id'] ?? '') ?: ensure_article_id($dir);
$status = (string)($state['status'] ?? '');
$locked = is_dir($dir . '/.movmaker-lock');
- if ($locked || $status === 'processing') {
+ if ($locked) {
$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'] ?? '');
@@ -1544,7 +1543,7 @@ $runningJobs = active_worker_jobs($config);
=h($err)?>
Videos without input dir
No orphan videos.
=page_links('videos',$videoPage,$videoPages)?>
-No input directories yet.
(string)($data['title'] ?? ''),'teaser'=>(string)($data['teaser'] ?? ''),'date'=>(string)($data['date'] ?? ''),'location'=>(string)($data['place'] ?? ''),'quote_da'=>(string)($data['quote_da'] ?? ''),'description'=>(string)($data['description'] ?? '')]; $currentSignature=$info['signature'] ?? ''; $fullFingerprint=is_array($state)?(string)($state['fingerprint'] ?? ''):''; $previewFingerprint=is_array($state)?(string)($state['preview_fingerprint'] ?? ''):''; $editedSinceRender=$hasFullVideo && $currentSignature !== '' && $fullFingerprint !== '' && $currentSignature !== $fullFingerprint; $editedSincePreview=!$hasFullVideo && $previewVideo && $currentSignature !== '' && $previewFingerprint !== '' && $currentSignature !== $previewFingerprint; $staleLabel=$editedSinceRender ? 'Edited since render' : ($editedSincePreview ? 'Edited since preview' : ''); ?>
Thumb source: =h((string)$thumbMeta['source_file'])?>
+
No input directories yet.
(string)($data['title'] ?? ''),'teaser'=>(string)($data['teaser'] ?? ''),'date'=>(string)($data['date'] ?? ''),'location'=>(string)($data['place'] ?? ''),'quote_da'=>(string)($data['quote_da'] ?? ''),'description'=>(string)($data['description'] ?? '')]; $currentSignature=$info['signature'] ?? ''; $fullFingerprint=is_array($state)?(string)($state['fingerprint'] ?? ''):''; $previewFingerprint=is_array($state)?(string)($state['preview_fingerprint'] ?? ''):''; $editedSinceRender=$hasFullVideo && $currentSignature !== '' && $fullFingerprint !== '' && $currentSignature !== $fullFingerprint; $editedSincePreview=!$hasFullVideo && $previewVideo && $currentSignature !== '' && $previewFingerprint !== '' && $currentSignature !== $previewFingerprint; $staleLabel=$editedSinceRender ? 'Edited since render' : ($editedSincePreview ? 'Edited since preview' : ''); ?>
Thumb source: =h((string)$thumbMeta['source_file'])?>
-
=h($meta['date'])?>=h($meta['location'])?>
=h((string)$meta['teaser'])?>
=nl2br(h($meta['description']), false)?>
โ=h(trim((string)$meta['quote_da'], "\"โโ"))?>โ
=h(implode(' ยท ', $detailParts))?>
=page_links('edit',$editPage,$editPages)?>
+
=h($meta['date'])?>=h($meta['location'])?>
=h((string)$meta['teaser'])?>
=nl2br(h($meta['description']), false)?>
โ=h(trim((string)$meta['quote_da'], "\"โโ"))?>โ
=h(implode(' ยท ', $detailParts))?>
=page_links('edit',$editPage,$editPages)?>
Edit input dir
in-dir/=h(basename($editDir))?>
This input directory is =h($editStatus)?>. Editing is disabled until the job completes.
@@ -2087,27 +2086,31 @@ function updateAdminRowTitleLink(row){
function rowPublicLocked(row){
return !!row && row.dataset.publicLocked === '1';
}
+function rowRunning(row){
+ return !!row && row.dataset.running === '1';
+}
function updatePublicLockedControls(row){
if(!row) return;
const locked = rowPublicLocked(row);
+ const running = rowRunning(row);
['preview','render','hide-map'].forEach(function(type){
const input = row.querySelector('form[data-switch="'+type+'"] input[type="checkbox"]');
if(input) input.disabled = locked;
});
const describe = row.querySelector('.describe-button');
if(describe){
- describe.classList.toggle('disabled', locked);
- describe.setAttribute('aria-disabled', locked ? 'true' : 'false');
- describe.title = locked ? 'Disable Show and Permalink before describing' : '';
+ describe.classList.toggle('disabled', running);
+ describe.setAttribute('aria-disabled', running ? 'true' : 'false');
+ describe.title = running ? 'Rendering now' : '';
}
const edit = row.querySelector('[data-edit-action="1"]');
if(edit && edit.tagName === 'A'){
if(!edit.dataset.editHref) edit.dataset.editHref = edit.getAttribute('href') || '';
- if(locked){
+ if(running){
edit.removeAttribute('href');
edit.classList.add('disabled');
edit.setAttribute('aria-disabled', 'true');
- edit.title = 'Disable Show and Permalink before editing';
+ edit.title = 'Rendering now';
}else{
const href = edit.dataset.editHref || '';
if(href) edit.setAttribute('href', href);
@@ -2146,6 +2149,9 @@ function applySwitchPayload(payload){
row.classList.toggle('shown', !!payload.visible);
row.dataset.visible = payload.visible ? '1' : '0';
}
+ if('running' in payload){
+ row.dataset.running = payload.running ? '1' : '0';
+ }
if('public_locked' in payload){
row.dataset.publicLocked = payload.public_locked ? '1' : '0';
}else{
@@ -2234,6 +2240,7 @@ document.addEventListener('DOMContentLoaded', function(){
const edit=row.querySelector('[data-edit-action="1"]');
if(!edit) return;
const running=(articleId && runningIds.has(articleId)) || runningJobs.has(job);
+ row.dataset.running = running ? '1' : '0';
if(edit.tagName === 'A'){
if(running){
if(!edit.dataset.editHref) edit.dataset.editHref = edit.getAttribute('href') || '';
diff --git a/job_status.php b/job_status.php
index 25916cf..b9bfbdc 100644
--- a/job_status.php
+++ b/job_status.php
@@ -75,6 +75,7 @@ function mvlog_input_dir_switch_payload(string $dir, array $config, string $arti
$canShow = mvlog_input_dir_can_show($dir, $config);
$visible = $canShow && mvlog_input_dir_visible_marker($dir);
$permalink = mvlog_input_dir_permalink($dir);
+ $running = is_dir($dir . '/.movmaker-lock');
return [
'dir' => basename($dir),
'id' => $articleId,
@@ -86,6 +87,7 @@ function mvlog_input_dir_switch_payload(string $dir, array $config, string $arti
'can_permalink' => $canShow,
'public_locked' => $visible || $permalink,
'map_hidden' => is_file($dir . '/.mvlog-hide-map'),
+ 'running' => $running,
];
}
@@ -142,7 +144,7 @@ foreach ($dirs as $dir) {
$switches[] = mvlog_input_dir_switch_payload($dir, $config, $articleId);
- if ($locked || $status === 'processing') {
+ if ($locked) {
$started = '';
if (is_file($lockDir . '/started_at')) $started = trim((string)file_get_contents($lockDir . '/started_at'));
if ($started === '') $started = (string)($state['started_at'] ?? $state['updated_at'] ?? '');