这这是一个基于PHP和JavaScript的命令执行工具,用于执行系统级别的视频处理脚本。该工具提供了一个Web界面,允许用户通过点击按钮执行预定义的shell脚本。
我运行的脚本命令是下面三条,可用根据自己的需要写出自己需要运行的脚本命令。
sudo -u fnos /home/liaozhenqiang/flv-to-mp4.sh sudo -u fnos /home/liaozhenqiang/flv-rename.sh sudo -u fnos /home/liaozhenqiang/stop-flv.sh
主要功能
三个功能按钮:
FLV转MP4
FLV重命名
停止FLV
处理实时日志显示:执行命令时显示实时输出结果异步执行:使用 AJAX 实现后台执行,不阻塞界面。
<?php
// 危险警告!此代码完全不考虑安全性,仅用于本地测试!
// 允许执行的命令列表(直接以root权限执行)
$allowedCommands = [
'flv-to-mp4' => 'sudo -u liaozhenqiang /home/liaozhenqiang/flv-to-mp4.sh',
'flv-rename' => 'sudo -u liaozhenqiang /home/liaozhenqiang/flv-rename.sh',
'stop-flv' => 'sudo -u liaozhenqiang /home/liaozhenqiang/stop-flv.sh'
];
// 执行结果
$result = [];
// 处理AJAX请求
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['command'])) {
$commandKey = $_POST['command'];
// 检查命令是否存在
if (isset($allowedCommands[$commandKey])) {
$command = $allowedCommands[$commandKey];
// 执行命令(直接使用exec,不做任何安全过滤)
exec($command . ' 2>&1', $output, $returnCode);
$result = [
'success' => $returnCode === 0,
'output' => implode("\n", $output),
'returnCode' => $returnCode
];
} else {
$result = [
'success' => false,
'error' => '未知命令'
];
}
// 返回JSON响应
header('Content-Type: application/json');
echo json_encode($result);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FLV转MP4脚本执行器</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 配置Tailwind主题 -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
danger: '#EF4444',
warning: '#F59E0B',
success: '#10B981',
dark: '#1F2937',
light: '#F9FAFB'
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.command-card {
@apply bg-white rounded-lg shadow-md p-5 transition-all duration-300 hover:shadow-lg transform hover:-translate-y-1;
}
.btn-execute {
@apply w-full py-3 font-medium rounded-lg transition-all duration-200 flex items-center justify-center;
}
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<header class="mb-8 text-center">
<div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-danger/10 mb-4">
<i class="fa fa-exclamation-triangle text-danger text-2xl"></i>
</div>
<h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-gray-800 mb-2">FLV转MP4脚本执行器</h1>
<p class="text-danger font-medium mb-2">警告:此工具以root权限执行命令,仅用于本地测试!</p>
<p>执行系统命令可能导致不可逆的系统变更,请谨慎操作</p>
</header>
<main>
<!-- 命令按钮区域 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- FLV转MP4按钮 -->
<div class="command-card border-l-4 border-primary">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-4">
<i class="fa fa-video-camera text-primary text-xl"></i>
</div>
<h2 class="text-xl font-semibold text-gray-800">FLV转MP4</h2>
</div>
<p class="text-gray-600 mb-4">执行视频格式转换脚本</p>
<button id="btn-flv-to-mp4" class="btn-execute bg-success hover:bg-primary/90 text-white">
<i class="fa fa-play-circle mr-2"></i> 执行转换
</button>
</div>
<!-- FLV重命名按钮 -->
<div class="command-card border-l-4 border-warning">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-warning/10 flex items-center justify-center mr-4">
<i class="fa fa-file-text-o text-warning text-xl"></i>
</div>
<h2 class="text-xl font-semibold text-gray-800">FLV重命名</h2>
</div>
<p class="text-gray-600 mb-4">执行文件重命名脚本</p>
<button id="btn-flv-rename" class="btn-execute bg-warning hover:bg-warning/90 text-white">
<i class="fa fa-play-circle mr-2"></i> 执行重命名
</button>
</div>
<!-- 停止FLV处理按钮 -->
<div class="command-card border-l-4 border-danger">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-danger/10 flex items-center justify-center mr-4">
<i class="fa fa-stop-circle text-danger text-xl"></i>
</div>
<h2 class="text-xl font-semibold text-gray-800">停止FLV处理</h2>
</div>
<p class="text-gray-600 mb-4">执行停止脚本,终止处理进程</p>
<button id="btn-stop-flv" class="btn-execute bg-danger hover:bg-danger/90 text-white">
<i class="fa fa-play-circle mr-2"></i> 停止处理
</button>
</div>
</div>
<!-- 日志显示区域 -->
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<div class="p-4 bg-gray-50 border-b border-gray-200 flex justify-between items-center">
<h3 class="font-semibold text-gray-800">执行日志</h3>
<button id="btn-clear-log" class="text-gray-600 hover:text-gray-900 transition-colors duration-200 flex items-center">
<i class="fa fa-trash-o mr-1"></i> 清空日志
</button>
</div>
<div id="log-container" class="h-80 p-4 overflow-y-auto bg-gray-900 text-gray-100 font-mono text-sm">
<div class="text-gray-400 italic">等待命令执行...</div>
</div>
</div>
</main>
<footer class="mt-12 text-center text-gray-500 text-sm">
<p>此工具仅供 <a href="https://lzq520.cn" style="color: red;" id="link"></a> 开发者本地测试使用,不要在生产环境中运行</p>
<script>
// 目标网址(需确认该网站允许跨域访问)
const targetUrl = 'https://lzq520.cn';
// 使用 fetch API 直接请求目标网址
fetch(targetUrl)
.then(response => {
if (!response.ok) throw new Error(`HTTP错误,状态码:${response.status}`);
return response.text(); // 获取HTML内容
})
.then(html => {
// 使用 DOMParser 解析 HTML 字符串
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const title = doc.title || '无标题'; // 获取<title>标签内容
// 设置到链接文本
document.getElementById('link').textContent = title;
})
.catch(error => {
console.error('获取标题失败:', error);
document.getElementById('link').textContent = '毒蘑菇炖鸡';
});
</script>
</footer>
</div>
<script>
// 按钮和日志容器
const btnFlvToMp4 = document.getElementById('btn-flv-to-mp4');
const btnFlvRename = document.getElementById('btn-flv-rename');
const btnStopFlv = document.getElementById('btn-stop-flv');
const btnClearLog = document.getElementById('btn-clear-log');
const logContainer = document.getElementById('log-container');
// 命令映射
const commandMap = {
'btn-flv-to-mp4': 'flv-to-mp4',
'btn-flv-rename': 'flv-rename',
'btn-stop-flv': 'stop-flv'
};
// 为按钮添加点击事件
[btnFlvToMp4, btnFlvRename, btnStopFlv].forEach(button => {
button.addEventListener('click', function() {
const commandKey = commandMap[this.id];
executeCommand(commandKey, this);
});
});
// 清空日志按钮事件
btnClearLog.addEventListener('click', function() {
logContainer.innerHTML = '<div class="text-gray-400 italic">日志已清空</div>';
});
// 执行命令函数
function executeCommand(commandKey, button) {
// 记录开始时间
const startTime = new Date();
// 禁用按钮
button.disabled = true;
button.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i> 执行中...';
// 添加执行日志
addLog(`<span>> 正在执行命令: ${commandKey}</span>`);
// 发送AJAX请求
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `command=${encodeURIComponent(commandKey)}`
})
.then(response => response.json())
.then(data => {
// 计算执行时间
const endTime = new Date();
const executionTime = (endTime - startTime) / 1000;
if (data.success) {
addLog(`<span>✓ 命令执行成功 (耗时: ${executionTime.toFixed(2)}s)</span>`);
addLog(data.output || '命令执行完毕,但没有输出');
} else {
addLog(`<span>✗ 命令执行失败 (耗时: ${executionTime.toFixed(2)}s)</span>`);
addLog(data.error || '未知错误');
}
// 恢复按钮状态
button.disabled = false;
button.innerHTML = '<i class="fa fa-play-circle mr-2"></i> 执行' +
(commandKey === 'flv-to-mp4' ? '转换' :
commandKey === 'flv-rename' ? '重命名' : '处理');
})
.catch(error => {
// 计算执行时间
const endTime = new Date();
const executionTime = (endTime - startTime) / 1000;
addLog(`<span>✗ 请求失败 (耗时: ${executionTime.toFixed(2)}s)</span>`);
addLog(error.message || '网络错误');
// 恢复按钮状态
button.disabled = false;
button.innerHTML = '<i class="fa fa-play-circle mr-2"></i> 执行' +
(commandKey === 'flv-to-mp4' ? '转换' :
commandKey === 'flv-rename' ? '重命名' : '处理');
});
}
// 添加日志到容器
function addLog(message) {
const logEntry = document.createElement('div');
logEntry.innerHTML = message;
logContainer.appendChild(logEntry);
logContainer.scrollTop = logContainer.scrollHeight;
}
</script>
</body>
</html>
新添加了一个有密码版本账户是:admin 密码:password123
<?php // 危险警告!此代码完全不考虑安全性,仅用于本地测试! // 允许执行的命令列表(直接以root权限执行) $allowedCommands = [ 'flv-to-mp4' => 'sudo -u liaozhenqiang /home/liaozhenqiang/flv-to-mp4.sh', 'flv-rename' => 'sudo -u liaozhenqiang /home/liaozhenqiang/flv-rename.sh', 'stop-flv' => 'sudo -u liaozhenqiang /home/liaozhenqiang/stop-flv.sh' ]; // 账户密码配置(实际使用中应使用加密存储) $validUsers = [ 'admin' => 'password123' // 用户名 => 密码,实际环境需加密存储 ]; // 执行结果 $result = []; // 初始化会话 session_start(); // 处理登录请求 if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) { $username = $_POST['username'] ?? ''; $password = $_POST['password'] ?? ''; if (isset($validUsers[$username]) && $validUsers[$username] === $password) { // 登录成功,设置会话 $_SESSION['authenticated'] = true; $_SESSION['username'] = $username; $result = [ 'success' => true, 'message' => '登录成功' ]; } else { $result = [ 'success' => false, 'error' => '用户名或密码错误' ]; } header('Content-Type: application/json'); echo json_encode($result); exit; } // 处理登出请求 if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['logout'])) { session_destroy(); $result = [ 'success' => true, 'message' => '已登出' ]; header('Content-Type: application/json'); echo json_encode($result); exit; } // 处理认证状态检查请求 if (isset($_GET['checkauth'])) { $result = [ 'authenticated' => isset($_SESSION['authenticated']) && $_SESSION['authenticated'] === true ]; header('Content-Type: application/json'); echo json_encode($result); exit; } // 检查是否已认证 $isAuthenticated = isset($_SESSION['authenticated']) && $_SESSION['authenticated'] === true; // 处理AJAX命令请求 if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['command'])) { // 验证是否已登录 if (!$isAuthenticated) { $result = [ 'success' => false, 'error' => '请先登录' ]; header('Content-Type: application/json'); echo json_encode($result); exit; } $commandKey = $_POST['command']; // 检查命令是否存在 if (isset($allowedCommands[$commandKey])) { $command = $allowedCommands[$commandKey]; // 执行命令(直接使用exec,不做任何安全过滤) exec($command . ' 2>&1', $output, $returnCode); $result = [ 'success' => $returnCode === 0, 'output' => implode("\n", $output), 'returnCode' => $returnCode ]; } else { $result = [ 'success' => false, 'error' => '未知命令' ]; } // 返回JSON响应 header('Content-Type: application/json'); echo json_encode($result); exit; } ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FLV转MP4脚本执行器</title> <script src="https://cdn.tailwindcss.com"></script> <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"> <!-- 配置Tailwind主题 --> <script> tailwind.config = { theme: { extend: { colors: { danger: '#EF4444', warning: '#F59E0B', success: '#10B981', dark: '#1F2937', light: '#F9FAFB', primary: '#3B82F6' }, fontFamily: { sans: ['Inter', 'system-ui', 'sans-serif'], }, } } } </script> <!-- 自定义工具类 --> <style type="text/tailwindcss"> @layer utilities { .content-auto { content-visibility: auto; } .command-card { @apply bg-white rounded-lg shadow-md p-5 transition-all duration-300 hover:shadow-lg transform hover:-translate-y-1; } .btn-execute { @apply w-full py-3 font-medium rounded-lg transition-all duration-200 flex items-center justify-center; } .auth-overlay { @apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50; } .auth-card { @apply bg-white rounded-lg shadow-xl p-8 w-full max-w-md; } } </style> </head> <body class="bg-gray-50 min-h-screen"> <div class="container mx-auto px-4 py-8 max-w-6xl"> <header class="mb-8 text-center"> <div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-danger/10 mb-4"> <i class="fa fa-exclamation-triangle text-danger text-2xl"></i> </div> <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-gray-800 mb-2">FLV转MP4脚本执行器</h1> <p class="text-danger font-medium mb-2">警告:此工具以root权限执行命令,仅用于本地测试!</p> <p>执行系统命令可能导致不可逆的系统变更,请谨慎操作</p> <div id="auth-status" class="mt-4 text-sm font-medium hidden"></div> </header> <main> <!-- 命令按钮区域 --> <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <!-- FLV转MP4按钮 --> <div class="command-card border-l-4 border-primary"> <div class="flex items-center mb-4"> <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-4"> <i class="fa fa-video-camera text-primary text-xl"></i> </div> <h2 class="text-xl font-semibold text-gray-800">FLV转MP4</h2> </div> <p class="text-gray-600 mb-4">执行视频格式转换脚本</p> <button id="btn-flv-to-mp4" class="btn-execute bg-success hover:bg-primary/90 text-white"> <i class="fa fa-play-circle mr-2"></i> 执行转换 </button> </div> <!-- FLV重命名按钮 --> <div class="command-card border-l-4 border-warning"> <div class="flex items-center mb-4"> <div class="w-10 h-10 rounded-full bg-warning/10 flex items-center justify-center mr-4"> <i class="fa fa-file-text-o text-warning text-xl"></i> </div> <h2 class="text-xl font-semibold text-gray-800">FLV重命名</h2> </div> <p class="text-gray-600 mb-4">执行文件重命名脚本</p> <button id="btn-flv-rename" class="btn-execute bg-warning hover:bg-warning/90 text-white"> <i class="fa fa-play-circle mr-2"></i> 执行重命名 </button> </div> <!-- 停止FLV处理按钮 --> <div class="command-card border-l-4 border-danger"> <div class="flex items-center mb-4"> <div class="w-10 h-10 rounded-full bg-danger/10 flex items-center justify-center mr-4"> <i class="fa fa-stop-circle text-danger text-xl"></i> </div> <h2 class="text-xl font-semibold text-gray-800">停止FLV处理</h2> </div> <p class="text-gray-600 mb-4">执行停止脚本,终止处理进程</p> <button id="btn-stop-flv" class="btn-execute bg-danger hover:bg-danger/90 text-white"> <i class="fa fa-play-circle mr-2"></i> 停止处理 </button> </div> </div> <!-- 日志显示区域 --> <div class="bg-white rounded-lg shadow-md overflow-hidden"> <div class="p-4 bg-gray-50 border-b border-gray-200 flex justify-between items-center"> <h3 class="font-semibold text-gray-800">执行日志</h3> <div class="flex gap-4"> <button id="btn-logout" class="text-gray-600 hover:text-gray-900 transition-colors duration-200 flex items-center hidden"> <i class="fa fa-sign-out mr-1"></i> 退出登录 </button> <button id="btn-clear-log" class="text-gray-600 hover:text-gray-900 transition-colors duration-200 flex items-center"> <i class="fa fa-trash-o mr-1"></i> 清空日志 </button> </div> </div> <div id="log-container" class="h-80 p-4 overflow-y-auto bg-gray-900 text-gray-100 font-mono text-sm"> <div class="text-gray-400 italic">等待命令执行...</div> </div> </div> </main> <footer class="mt-12 text-center text-gray-500 text-sm"> <p>此工具仅供 <a href="https://lzq520.cn" style="color: red;" id="link"></a> 开发者本地测试使用,不要在生产环境中运行</p> <script> // 目标网址(需确认该网站允许跨域访问) const targetUrl = 'https://lzq520.cn'; // 使用 fetch API 直接请求目标网址 fetch(targetUrl) .then(response => { if (!response.ok) throw new Error(`HTTP错误,状态码:${response.status}`); return response.text(); // 获取HTML内容 }) .then(html => { // 使用 DOMParser 解析 HTML 字符串 const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const title = doc.title || '无标题'; // 获取<title>标签内容 // 设置到链接文本 document.getElementById('link').textContent = title; }) .catch(error => { console.error('获取标题失败:', error); document.getElementById('link').textContent = '毒蘑菇炖鸡'; }); </script> </footer> </div> <!-- 登录弹窗 --> <div id="login-modal" class="auth-overlay hidden"> <div> <h2 class="text-2xl font-bold text-center mb-6">请登录</h2> <form id="login-form"> <div> <label for="username" class="block text-gray-700 mb-2">用户名</label> <input type="text" id="username" name="username" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary" required> </div> <div> <label for="password" class="block text-gray-700 mb-2">密码</label> <input type="password" id="password" name="password" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary" required> </div> <button type="submit" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-colors duration-200"> 登录 </button> <div id="login-error" class="mt-4 text-red-500 text-sm text-center hidden"></div> </form> </div> </div> <script> // 按钮和日志容器 const btnFlvToMp4 = document.getElementById('btn-flv-to-mp4'); const btnFlvRename = document.getElementById('btn-flv-rename'); const btnStopFlv = document.getElementById('btn-stop-flv'); const btnClearLog = document.getElementById('btn-clear-log'); const btnLogout = document.getElementById('btn-logout'); const logContainer = document.getElementById('log-container'); const authStatus = document.getElementById('auth-status'); const loginModal = document.getElementById('login-modal'); const loginForm = document.getElementById('login-form'); const loginError = document.getElementById('login-error'); // 命令映射 const commandMap = { 'btn-flv-to-mp4': 'flv-to-mp4', 'btn-flv-rename': 'flv-rename', 'btn-stop-flv': 'stop-flv' }; // 检查登录状态 - 使用专用API端点 function checkAuthStatus() { return fetch('?checkauth=true') .then(response => response.json()) .then(data => { updateAuthUI(data.authenticated); return data.authenticated; }) .catch(error => { console.error('检查登录状态失败:', error); return false; }); } // 更新登录状态UI function updateAuthUI(isAuthenticated) { if (isAuthenticated) { // 确保登录窗口关闭 loginModal.classList.add('hidden'); loginModal.style.display = 'none'; authStatus.classList.remove('hidden'); authStatus.classList.add('text-success'); authStatus.innerHTML = '<i class="fa fa-check-circle mr-1"></i> 已登录'; btnLogout.classList.remove('hidden'); // 启用命令按钮 [btnFlvToMp4, btnFlvRename, btnStopFlv].forEach(btn => { btn.disabled = false; }); } else { // 显示登录窗口 loginModal.classList.remove('hidden'); loginModal.style.display = 'flex'; authStatus.classList.add('hidden'); btnLogout.classList.add('hidden'); // 禁用命令按钮 [btnFlvToMp4, btnFlvRename, btnStopFlv].forEach(btn => { btn.disabled = true; }); } } // 页面加载时检查登录状态 document.addEventListener('DOMContentLoaded', () => { checkAuthStatus(); }); // 登录表单提交 loginForm.addEventListener('submit', async function(e) { e.preventDefault(); const formData = new FormData(); formData.append('login', 'true'); formData.append('username', document.getElementById('username').value); formData.append('password', document.getElementById('password').value); try { const response = await fetch('', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { // 登录成功后清空错误信息 loginError.classList.add('hidden'); addLog('<span>✓ 登录成功</span>'); // 重置表单 loginForm.reset(); // 强制刷新认证状态并关闭窗口 const isAuthenticated = await checkAuthStatus(); if (isAuthenticated) { loginModal.classList.add('hidden'); loginModal.style.display = 'none'; } } else { // 显示错误信息 loginError.textContent = data.error || '登录失败'; loginError.classList.remove('hidden'); } } catch (error) { console.error('登录请求失败:', error); loginError.textContent = '网络错误,请重试'; loginError.classList.remove('hidden'); } }); // 登出功能 btnLogout.addEventListener('click', function() { fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'logout=true' }) .then(response => response.json()) .then(data => { if (data.success) { addLog('<span>⚠️ 已登出</span>'); updateAuthUI(false); } }) .catch(error => { console.error('登出请求失败:', error); }); }); // 为按钮添加点击事件 [btnFlvToMp4, btnFlvRename, btnStopFlv].forEach(button => { button.addEventListener('click', function() { const commandKey = commandMap[this.id]; executeCommand(commandKey, this); }); }); // 清空日志按钮事件 btnClearLog.addEventListener('click', function() { logContainer.innerHTML = '<div class="text-gray-400 italic">等待命令执行...</div>'; }); // 执行命令函数 function executeCommand(commandKey, button) { // 记录开始时间 const startTime = new Date(); // 禁用按钮 button.disabled = true; button.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i> 执行中...'; // 添加执行日志 addLog(`<span>> 正在执行命令: ${commandKey}</span>`); // 发送AJAX请求 fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `command=${encodeURIComponent(commandKey)}` }) .then(response => response.json()) .then(data => { // 计算执行时间 const endTime = new Date(); const executionTime = (endTime - startTime) / 1000; if (data.success) { addLog(`<span>✓ 命令执行成功 (耗时: ${executionTime.toFixed(2)}s)</span>`); addLog(data.output || '命令执行完毕,但没有输出'); } else { // 处理未登录错误 if (data.error === '请先登录') { updateAuthUI(false); } addLog(`<span>✗ 命令执行失败 (耗时: ${executionTime.toFixed(2)}s)</span>`); addLog(data.error || '未知错误'); } // 恢复按钮状态 button.disabled = false; button.innerHTML = '<i class="fa fa-play-circle mr-2"></i> 执行' + (commandKey === 'flv-to-mp4' ? '转换' : commandKey === 'flv-rename' ? '重命名' : '处理'); }) .catch(error => { // 计算执行时间 const endTime = new Date(); const executionTime = (endTime - startTime) / 1000; addLog(`<span>✗ 请求失败 (耗时: ${executionTime.toFixed(2)}s)</span>`); addLog(error.message || '网络错误'); // 恢复按钮状态 button.disabled = false; button.innerHTML = '<i class="fa fa-play-circle mr-2"></i> 执行' + (commandKey === 'flv-to-mp4' ? '转换' : commandKey === 'flv-rename' ? '重命名' : '处理'); }); } // 添加日志到容器 function addLog(message) { const logEntry = document.createElement('div'); logEntry.innerHTML = message; logContainer.appendChild(logEntry); logContainer.scrollTop = logContainer.scrollHeight; } </script> </body> </html>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 1963849530@qq.com 举报,一经查实,本站将立刻删除。如若转载,请注明出处:https://lzq520.cn/narong/136.html