Cache admin input directory metadata
This commit is contained in:
parent
fcae25d28a
commit
d4c5e532cb
1 changed files with 83 additions and 13 deletions
96
new.php
96
new.php
|
|
@ -3,7 +3,9 @@ require __DIR__ . '/auth.php';
|
||||||
mvlog_require_login();
|
mvlog_require_login();
|
||||||
$config = require __DIR__ . "/config.php";
|
$config = require __DIR__ . "/config.php";
|
||||||
foreach (["videos_dir", "thumbs_dir", "uploads_dir"] as $d) if (!is_dir($config[$d])) mkdir($config[$d], 0775, true);
|
foreach (["videos_dir", "thumbs_dir", "uploads_dir"] as $d) if (!is_dir($config[$d])) mkdir($config[$d], 0775, true);
|
||||||
|
if (!is_dir(__DIR__ . "/cache")) mkdir(__DIR__ . "/cache", 0775, true);
|
||||||
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, "UTF-8"); }
|
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, "UTF-8"); }
|
||||||
|
function ajax_json($data){ header('Content-Type: application/json; charset=UTF-8'); echo json_encode($data, JSON_UNESCAPED_UNICODE); exit; }
|
||||||
function slugify($s){ $s = strtolower(trim($s)); $s = preg_replace('/[^a-z0-9]+/', '-', $s); return trim($s, '-') ?: 'movie'; }
|
function slugify($s){ $s = strtolower(trim($s)); $s = preg_replace('/[^a-z0-9]+/', '-', $s); return trim($s, '-') ?: 'movie'; }
|
||||||
function rrmdir($dir){ if(!is_dir($dir)) return; foreach(scandir($dir) as $f){ if($f==='.'||$f==='..') continue; $p="$dir/$f"; is_dir($p)?rrmdir($p):unlink($p);} rmdir($dir); }
|
function rrmdir($dir){ if(!is_dir($dir)) return; foreach(scandir($dir) as $f){ if($f==='.'||$f==='..') continue; $p="$dir/$f"; is_dir($p)?rrmdir($p):unlink($p);} rmdir($dir); }
|
||||||
function input_dirs($base){ return glob($base.'/*', GLOB_ONLYDIR) ?: []; }
|
function input_dirs($base){ return glob($base.'/*', GLOB_ONLYDIR) ?: []; }
|
||||||
|
|
@ -133,13 +135,54 @@ function unique_input_dir($base, $slug){
|
||||||
if (!file_exists($candidate)) return $candidate;
|
if (!file_exists($candidate)) return $candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function input_dir_sort_date($dir){
|
function input_dir_signature($dir){
|
||||||
$data = read_data($dir);
|
$entries = [];
|
||||||
return input_dir_date_from_text($data['date'] ?? '') ?? input_dir_date_from_media($dir);
|
foreach (scandir($dir) ?: [] as $file) {
|
||||||
|
if ($file === '.' || $file === '..' || in_array($file, ['.movmaker-state.json','.movmaker-enabled','.mvlog-hidden'], true)) continue;
|
||||||
|
if ($file === '.movmaker-lock') continue;
|
||||||
|
$path = $dir . '/' . $file;
|
||||||
|
if (is_file($path)) $entries[] = [$file, filesize($path), filemtime($path)];
|
||||||
|
}
|
||||||
|
sort($entries);
|
||||||
|
return hash('sha256', json_encode($entries, JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
function sort_input_dirs_by_metadata_date(&$dirs){
|
function input_dir_info($dir){
|
||||||
usort($dirs, function($a, $b) {
|
$data = read_data($dir);
|
||||||
$cmp = strcmp(input_dir_sort_date($b), input_dir_sort_date($a));
|
$files = list_files($dir);
|
||||||
|
return [
|
||||||
|
'name' => basename($dir),
|
||||||
|
'title' => $data['title'] ?: basename($dir),
|
||||||
|
'sort_date' => input_dir_date_from_text($data['date'] ?? '') ?? input_dir_date_from_media($dir),
|
||||||
|
'file_count' => count($files),
|
||||||
|
'signature' => input_dir_signature($dir),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
function load_input_dir_cache($dirs){
|
||||||
|
$cacheFile = __DIR__ . '/cache/input-dirs.json';
|
||||||
|
$cache = is_file($cacheFile) ? json_decode((string)file_get_contents($cacheFile), true) : [];
|
||||||
|
if (!is_array($cache) || ($cache['version'] ?? 0) !== 1) $cache = ['version'=>1,'items'=>[]];
|
||||||
|
$oldItems = is_array($cache['items'] ?? null) ? $cache['items'] : [];
|
||||||
|
$items = []; $changed = false;
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
$name = basename($dir);
|
||||||
|
$sig = input_dir_signature($dir);
|
||||||
|
$cached = $oldItems[$name] ?? null;
|
||||||
|
if (is_array($cached) && ($cached['signature'] ?? '') === $sig) {
|
||||||
|
$items[$name] = $cached;
|
||||||
|
} else {
|
||||||
|
$items[$name] = input_dir_info($dir);
|
||||||
|
$changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_diff(array_keys($oldItems), array_keys($items))) $changed = true;
|
||||||
|
if ($changed) file_put_contents($cacheFile, json_encode(['version'=>1,'generated_at'=>date('c'),'items'=>$items], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX);
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
function sort_input_dirs_by_metadata_date(&$dirs, $dirInfo){
|
||||||
|
usort($dirs, function($a, $b) use ($dirInfo) {
|
||||||
|
$ad = $dirInfo[basename($a)]['sort_date'] ?? '00000000';
|
||||||
|
$bd = $dirInfo[basename($b)]['sort_date'] ?? '00000000';
|
||||||
|
$cmp = strcmp($bd, $ad);
|
||||||
return $cmp !== 0 ? $cmp : strnatcasecmp(basename($b), basename($a));
|
return $cmp !== 0 ? $cmp : strnatcasecmp(basename($b), basename($a));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -232,13 +275,17 @@ try {
|
||||||
$_GET['edit'] = $slug;
|
$_GET['edit'] = $slug;
|
||||||
} elseif ($action === 'set_enabled') {
|
} elseif ($action === 'set_enabled') {
|
||||||
$dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? '');
|
$dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? '');
|
||||||
set_input_dir_enabled($dir, !empty($_POST['enabled']));
|
$enabledNow = !empty($_POST['enabled']);
|
||||||
header('Location: new.php?tab=edit&msg=' . rawurlencode((!empty($_POST['enabled']) ? 'Enabled rendering for: in-dir/' : 'Disabled rendering for: in-dir/') . basename($dir)));
|
set_input_dir_enabled($dir, $enabledNow);
|
||||||
|
if (!empty($_POST['ajax'])) ajax_json(['ok'=>true, 'enabled'=>$enabledNow, 'dir'=>basename($dir)]);
|
||||||
|
header('Location: new.php?tab=edit&msg=' . rawurlencode(($enabledNow ? 'Enabled rendering for: in-dir/' : 'Disabled rendering for: in-dir/') . basename($dir)));
|
||||||
exit;
|
exit;
|
||||||
} elseif ($action === 'set_visible') {
|
} elseif ($action === 'set_visible') {
|
||||||
$dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? '');
|
$dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? '');
|
||||||
set_input_dir_visible($dir, !empty($_POST['visible']));
|
$visibleNow = !empty($_POST['visible']);
|
||||||
header('Location: new.php?tab=edit&msg=' . rawurlencode((!empty($_POST['visible']) ? 'Shown: in-dir/' : 'Hidden: in-dir/') . basename($dir)));
|
set_input_dir_visible($dir, $visibleNow);
|
||||||
|
if (!empty($_POST['ajax'])) ajax_json(['ok'=>true, 'visible'=>$visibleNow, 'dir'=>basename($dir)]);
|
||||||
|
header('Location: new.php?tab=edit&msg=' . rawurlencode(($visibleNow ? 'Shown: in-dir/' : 'Hidden: in-dir/') . basename($dir)));
|
||||||
exit;
|
exit;
|
||||||
} elseif ($action === 'update') {
|
} elseif ($action === 'update') {
|
||||||
$dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? '');
|
$dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? '');
|
||||||
|
|
@ -284,7 +331,8 @@ try {
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) { $err = $e->getMessage(); }
|
} catch (Throwable $e) { $err = $e->getMessage(); }
|
||||||
$dirs = input_dirs($config['uploads_dir']);
|
$dirs = input_dirs($config['uploads_dir']);
|
||||||
sort_input_dirs_by_metadata_date($dirs);
|
$dirInfo = load_input_dir_cache($dirs);
|
||||||
|
sort_input_dirs_by_metadata_date($dirs, $dirInfo);
|
||||||
$orphanVideos = orphan_videos($config);
|
$orphanVideos = orphan_videos($config);
|
||||||
$tab = $_GET['tab'] ?? (isset($_GET['edit']) ? 'edit' : 'new');
|
$tab = $_GET['tab'] ?? (isset($_GET['edit']) ? 'edit' : 'new');
|
||||||
$page = max(1, (int)($_GET['page'] ?? 1));
|
$page = max(1, (int)($_GET['page'] ?? 1));
|
||||||
|
|
@ -299,11 +347,33 @@ if ($editName !== '') { try { $editDir = safe_input_dir($config['uploads_dir'],
|
||||||
<?php if($msg): ?><div class="ok"><?=h($msg)?></div><?php endif; ?><?php if($err): ?><div class="err"><?=h($err)?></div><?php endif; ?>
|
<?php if($msg): ?><div class="ok"><?=h($msg)?></div><?php endif; ?><?php if($err): ?><div class="err"><?=h($err)?></div><?php endif; ?>
|
||||||
|
|
||||||
<?php if($tab==='videos'): ?><section><h2>Videos without input dir</h2><?php if(!$orphanVideos): ?><p>No orphan videos.</p><?php endif; ?><div class="admin-list"><?php foreach($orphanVideosPage as $v): $vn=basename($v); ?><form method="post" class="admin-item" onsubmit="return confirm('Delete this generated video?')"><div><strong><?=h($vn)?></strong><br><span><?=h(round(filesize($v)/1048576,1))?> MB</span></div><input type="hidden" name="action" value="delete_video"><input type="hidden" name="video" value="<?=h($vn)?>"><button type="submit">Delete video</button></form><?php endforeach; ?></div><?=page_links('videos',$videoPage,$videoPages)?></section><?php endif; ?>
|
<?php if($tab==='videos'): ?><section><h2>Videos without input dir</h2><?php if(!$orphanVideos): ?><p>No orphan videos.</p><?php endif; ?><div class="admin-list"><?php foreach($orphanVideosPage as $v): $vn=basename($v); ?><form method="post" class="admin-item" onsubmit="return confirm('Delete this generated video?')"><div><strong><?=h($vn)?></strong><br><span><?=h(round(filesize($v)/1048576,1))?> MB</span></div><input type="hidden" name="action" value="delete_video"><input type="hidden" name="video" value="<?=h($vn)?>"><button type="submit">Delete video</button></form><?php endforeach; ?></div><?=page_links('videos',$videoPage,$videoPages)?></section><?php endif; ?>
|
||||||
<?php if($tab==='edit'): ?><section><h2>Existing input dirs</h2><?php if(!$dirs): ?><p>No input directories yet.</p><?php endif; ?><div class="admin-list"><?php foreach($dirsPage as $d): $runStatus=input_dir_status($d); $running=$runStatus !== ''; $enabled=input_dir_enabled($d); $visible=input_dir_visible($d); $data=read_data($d); ?><div class="admin-item"><div class="admin-switches"><form method="post" class="inline-form"><input type="hidden" name="action" value="set_visible"><input type="hidden" name="dir" value="<?=h(basename($d))?>"><label class="switch-label"><input type="checkbox" name="visible" value="1" onchange="this.form.submit()" <?=$visible?'checked':''?>><span class="switch-ui" aria-hidden="true"></span><span class="switch-text">Show</span></label></form><form method="post" class="inline-form"><input type="hidden" name="action" value="set_enabled"><input type="hidden" name="dir" value="<?=h(basename($d))?>"><label class="switch-label"><input type="checkbox" name="enabled" value="1" onchange="this.form.submit()" <?=$enabled?'checked':''?>><span class="switch-ui" aria-hidden="true"></span><span class="switch-text">Run</span></label></form></div><div class="admin-main"><strong><?=h($data['title'] ?: basename($d))?></strong><br><span><?=h(basename($d))?> · <?=h(count(list_files($d)))?> files · <?= $enabled ? 'Rendering enabled' : 'Rendering disabled' ?> · <?= $visible ? 'Shown' : 'Hidden' ?><?= $running ? ' · '.h(ucfirst($runStatus)) : '' ?></span></div><div class="admin-actions"><?php if($running): ?><span class="button disabled" title="Rendering now"><?=h(ucfirst($runStatus))?></span><?php else: ?><a class="button" href="?edit=<?=rawurlencode(basename($d))?>">Edit</a><?php endif; ?></div></div><?php endforeach; ?></div><?=page_links('edit',$editPage,$editPages)?></section><?php endif; ?>
|
<?php if($tab==='edit'): ?><section><h2>Existing input dirs</h2><?php if(!$dirs): ?><p>No input directories yet.</p><?php endif; ?><div class="admin-list"><?php foreach($dirsPage as $d): $runStatus=input_dir_status($d); $running=$runStatus !== ''; $enabled=input_dir_enabled($d); $visible=input_dir_visible($d); $info=$dirInfo[basename($d)] ?? input_dir_info($d); ?><div class="admin-item"><div class="admin-switches"><form method="post" class="inline-form"><input type="hidden" name="action" value="set_visible"><input type="hidden" name="dir" value="<?=h(basename($d))?>"><label class="switch-label"><input type="checkbox" name="visible" value="1" onchange="this.form.submit()" <?=$visible?'checked':''?>><span class="switch-ui" aria-hidden="true"></span><span class="switch-text">Show</span></label></form><form method="post" class="inline-form"><input type="hidden" name="action" value="set_enabled"><input type="hidden" name="dir" value="<?=h(basename($d))?>"><label class="switch-label"><input type="checkbox" name="enabled" value="1" onchange="this.form.submit()" <?=$enabled?'checked':''?>><span class="switch-ui" aria-hidden="true"></span><span class="switch-text">Run</span></label></form></div><div class="admin-main"><strong><?=h($info['title'] ?? basename($d))?></strong><br><span><?=h(basename($d))?> · <?=h($info['file_count'] ?? count(list_files($d)))?> files · <?= $enabled ? 'Rendering enabled' : 'Rendering disabled' ?> · <?= $visible ? 'Shown' : 'Hidden' ?><?= $running ? ' · '.h(ucfirst($runStatus)) : '' ?></span></div><div class="admin-actions"><?php if($running): ?><span class="button disabled" title="Rendering now"><?=h(ucfirst($runStatus))?></span><?php else: ?><a class="button" href="?edit=<?=rawurlencode(basename($d))?>">Edit</a><?php endif; ?></div></div><?php endforeach; ?></div><?=page_links('edit',$editPage,$editPages)?></section><?php endif; ?>
|
||||||
<?php if($tab==='edit' && $editDir && $editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><div class="err">This input directory is <?=h($editStatus)?>. Editing is disabled until the job completes.</div></section><?php endif; ?>
|
<?php if($tab==='edit' && $editDir && $editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><div class="err">This input directory is <?=h($editStatus)?>. Editing is disabled until the job completes.</div></section><?php endif; ?>
|
||||||
<?php if($tab==='edit' && $editDir && !$editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><form method="post" enctype="multipart/form-data"><input type="hidden" name="action" value="update"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><label>Title<input name="title" value="<?=h($editData['title'])?>"></label><label>Date<input name="date" value="<?=h($editData['date'])?>"></label><label>Place<input name="place" value="<?=h($editData['place'])?>"></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-edit"><?=h($editData['description'])?></textarea><small id="description-counter-edit" class="counter"></small></label><label>Add images / videos<input type="file" name="media[]" multiple accept="image/*,video/*"></label><label>Add audio<input type="file" name="audio[]" multiple accept="audio/*"></label><h3>Files and captions</h3><div class="file-list"><?php foreach($editFiles as $f): $ext=strtolower(pathinfo($f, PATHINFO_EXTENSION)); $fileUrl='in-dir/'.rawurlencode(basename($editDir)).'/'.rawurlencode($f); ?><div class="caption-row"><div class="preview"><?php if(in_array($ext,['jpg','jpeg','png','webp','gif'])): ?><img src="<?=h($fileUrl)?>" alt=""><?php elseif(in_array($ext,['mp4','mov','m4v','webm'])): ?><video src="<?=h($fileUrl)?>" muted preload="metadata"></video><?php else: ?><span><?=h(strtoupper($ext ?: 'FILE'))?></span><?php endif; ?></div><div class="caption-fields"><strong><?=h($f)?></strong><?php if(in_array($ext,['jpg','jpeg','png','webp','gif','mp4','mov','m4v','webm'])): ?><input type="hidden" name="caption_files[]" value="<?=h($f)?>"><textarea name="captions[]" placeholder="Optional caption for this file"><?=h($editData['captions'][$f] ?? '')?></textarea><?php if(in_array($ext,['mp4','mov','m4v','webm'])): ?><label class="checkbox-label"><input type="checkbox" name="use_audio_files[]" value="<?=h($f)?>" <?=!empty($editData['video_audio'][$f])?'checked':''?>> <span>Use video file audio</span></label><?php endif; ?><?php else: ?><small>No caption for audio files</small><?php endif; ?></div><button type="button" onclick="deleteFile(<?=h(json_encode($f))?>)">Remove</button></div><?php endforeach; ?></div><button type="submit">Save changes</button></form><form method="post" id="delete-file-form" style="display:none"><input type="hidden" name="action" value="delete_file"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="file" id="delete-file-name" value=""></form><form method="post" onsubmit="return confirm('Delete this input directory?')"><input type="hidden" name="action" value="delete_dir"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><label class="checkbox-label"><input type="checkbox" name="delete_output" value="1"> <span>Also delete generated video, if any</span></label><button class="danger" type="submit">Delete input dir</button></form></section><?php endif; ?>
|
<?php if($tab==='edit' && $editDir && !$editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><form method="post" enctype="multipart/form-data"><input type="hidden" name="action" value="update"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><label>Title<input name="title" value="<?=h($editData['title'])?>"></label><label>Date<input name="date" value="<?=h($editData['date'])?>"></label><label>Place<input name="place" value="<?=h($editData['place'])?>"></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-edit"><?=h($editData['description'])?></textarea><small id="description-counter-edit" class="counter"></small></label><label>Add images / videos<input type="file" name="media[]" multiple accept="image/*,video/*"></label><label>Add audio<input type="file" name="audio[]" multiple accept="audio/*"></label><h3>Files and captions</h3><div class="file-list"><?php foreach($editFiles as $f): $ext=strtolower(pathinfo($f, PATHINFO_EXTENSION)); $fileUrl='in-dir/'.rawurlencode(basename($editDir)).'/'.rawurlencode($f); ?><div class="caption-row"><div class="preview"><?php if(in_array($ext,['jpg','jpeg','png','webp','gif'])): ?><img src="<?=h($fileUrl)?>" alt=""><?php elseif(in_array($ext,['mp4','mov','m4v','webm'])): ?><video src="<?=h($fileUrl)?>" muted preload="metadata"></video><?php else: ?><span><?=h(strtoupper($ext ?: 'FILE'))?></span><?php endif; ?></div><div class="caption-fields"><strong><?=h($f)?></strong><?php if(in_array($ext,['jpg','jpeg','png','webp','gif','mp4','mov','m4v','webm'])): ?><input type="hidden" name="caption_files[]" value="<?=h($f)?>"><textarea name="captions[]" placeholder="Optional caption for this file"><?=h($editData['captions'][$f] ?? '')?></textarea><?php if(in_array($ext,['mp4','mov','m4v','webm'])): ?><label class="checkbox-label"><input type="checkbox" name="use_audio_files[]" value="<?=h($f)?>" <?=!empty($editData['video_audio'][$f])?'checked':''?>> <span>Use video file audio</span></label><?php endif; ?><?php else: ?><small>No caption for audio files</small><?php endif; ?></div><button type="button" onclick="deleteFile(<?=h(json_encode($f))?>)">Remove</button></div><?php endforeach; ?></div><button type="submit">Save changes</button></form><form method="post" id="delete-file-form" style="display:none"><input type="hidden" name="action" value="delete_file"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="file" id="delete-file-name" value=""></form><form method="post" onsubmit="return confirm('Delete this input directory?')"><input type="hidden" name="action" value="delete_dir"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><label class="checkbox-label"><input type="checkbox" name="delete_output" value="1"> <span>Also delete generated video, if any</span></label><button class="danger" type="submit">Delete input dir</button></form></section><?php endif; ?>
|
||||||
<?php if($tab==='new'): ?><section><h2>Add new movie input</h2><form method="post" enctype="multipart/form-data"><input type="hidden" name="action" value="create"><label>Title*<input name="title" required></label><label>Date<input name="date" placeholder="2026-05-25"></label><label>Place<input name="place"></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-new"></textarea><small id="description-counter-new" class="counter"></small></label><label>Images / videos*<input type="file" name="media[]" multiple required accept="image/*,video/*"></label><label>Audio (optional)<input type="file" name="audio[]" multiple accept="audio/*"></label><button type="submit">Create input-dir</button></form></section><?php endif; ?>
|
<?php if($tab==='new'): ?><section><h2>Add new movie input</h2><form method="post" enctype="multipart/form-data"><input type="hidden" name="action" value="create"><label>Title*<input name="title" required></label><label>Date<input name="date" placeholder="2026-05-25"></label><label>Place<input name="place"></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-new"></textarea><small id="description-counter-new" class="counter"></small></label><label>Images / videos*<input type="file" name="media[]" multiple required accept="image/*,video/*"></label><label>Audio (optional)<input type="file" name="audio[]" multiple accept="audio/*"></label><button type="submit">Create input-dir</button></form></section><?php endif; ?>
|
||||||
<script>function deleteFile(name){if(confirm('Remove this file?')){document.getElementById('delete-file-name').value=name;document.getElementById('delete-file-form').submit();}}</script><script>
|
<script>function deleteFile(name){if(confirm('Remove this file?')){document.getElementById('delete-file-name').value=name;document.getElementById('delete-file-form').submit();}}</script>
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.admin-switches input[type="checkbox"]').forEach(function(input){
|
||||||
|
input.addEventListener('change', async function(){
|
||||||
|
const form=input.form;
|
||||||
|
const previous=!input.checked;
|
||||||
|
const data=new FormData(form);
|
||||||
|
data.set('ajax','1');
|
||||||
|
input.disabled=true;
|
||||||
|
try{
|
||||||
|
const res=await fetch('new.php',{method:'POST',body:data,credentials:'same-origin'});
|
||||||
|
const json=await res.json();
|
||||||
|
if(!res.ok || !json.ok) throw new Error('Switch update failed');
|
||||||
|
}catch(e){
|
||||||
|
input.checked=previous;
|
||||||
|
alert(e.message || 'Switch update failed');
|
||||||
|
}finally{
|
||||||
|
input.disabled=false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
(function(){
|
(function(){
|
||||||
const box=document.getElementById('job-status');
|
const box=document.getElementById('job-status');
|
||||||
if(!box) return;
|
if(!box) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue