This commit is contained in:
Your Name
2026-01-27 09:17:04 +00:00
parent 3ccbf3d973
commit 7ade49e46d
4 changed files with 157 additions and 70 deletions

View File

@@ -13,16 +13,17 @@ h1{margin:0 0 24px;font-size:1.6em;display:flex;align-items:center;gap:12px}
#processSelect{padding:8px;border-radius:8px;border:1px solid #ddd;font-size:1em}
#statusIndicator{font-size:1.2em;font-weight:600}
h2{margin:24px 0 12px;font-size:1.4em}
h3{margin:16px 0 8px;font-size:1.2em}
input,button,textarea{width:100%;padding:12px;margin:8px 0;border-radius:8px;border:none;box-sizing:border-box;font-size:1em}
input,textarea{background:#f5f5f5;color:#000;border:1px solid #ddd;font-family:monospace}
input,textarea{background:#f5f5f5;color:#000;border:1px solid #ddd;font-family:monospace;overflow:hidden;resize:none;min-height:100px}
button{background:var(--accent);color:#fff;cursor:pointer;font-weight:600;transition:.2s}
button:hover{background:#1a237e}
button.loading{opacity:.7;pointer-events:none}
button.loading::after{content:" ⏳";animation:spin 1s linear infinite}
#pm2Buttons{display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:8px;margin:12px 0}
#pm2Log{background:#000;color:#0f0;padding:12px;height:320px;overflow-y:auto;font-family:monospace;font-size:.9em;border-radius:8px;white-space:pre-wrap;word-break:break-all}
#configButtons{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin:12px 0}
#configStatus{color:#0f0;margin-top:8px;font-family:monospace}
.configButtons{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin:12px 0}
.configStatus{color:#0f0;margin-top:8px;font-family:monospace;font-size:0.9em}
#obsAddress{background:#f0f0f0;padding:12px;border-radius:8px;font-family:monospace;font-size:1.1em;margin:8px 0;word-break:break-all}
@keyframes spin{to{transform:rotate(360deg)}}
</style>
@@ -39,15 +40,32 @@ button.loading::after{content:" ⏳";animation:spin 1s linear infinite}
<span id="statusIndicator">⚪ 加载中...</span>
</h1>
<!-- YouTube 配置编辑区(仅 youtube 时显示) -->
<div id="configSection" style="display:none;">
<h2>YouTube 配置编辑 (config/youtube.ini)</h2>
<textarea id="youtubeConfig" rows="20"></textarea>
<div id="configButtons">
<button id="loadConfigBtn">加载配置</button>
<button id="saveConfigBtn">保存配置</button>
<!-- YouTube 专属配置(仅 youtube 时显示) -->
<div id="youtubeOnlySection" style="display:none;">
<h2>YouTube 配置编辑 (youtube.ini)</h2>
<div class="configEditor">
<h3>youtube.ini</h3>
<textarea id="youtubeConfig"></textarea>
<div class="configButtons">
<button id="loadYoutubeBtn">加载配置</button>
<button id="saveYoutubeBtn">保存配置</button>
</div>
<pre class="configStatus" id="youtubeStatus">就绪</pre>
</div>
</div>
<!-- URL_config.ini 共享配置youtube 或 tiktok 时显示) -->
<div id="urlConfigSection" style="display:none;">
<h2>URL 配置编辑 (URL_config.ini)</h2>
<div class="configEditor">
<h3>URL_config.ini</h3>
<textarea id="urlConfig"></textarea>
<div class="configButtons">
<button id="loadUrlBtn">加载配置</button>
<button id="saveUrlBtn">保存配置</button>
</div>
<pre class="configStatus" id="urlStatus">就绪</pre>
</div>
<pre id="configStatus">就绪</pre>
</div>
<!-- OBS 推流地址区(仅 obs 时显示) -->
@@ -75,12 +93,21 @@ const processSelect = document.getElementById('processSelect');
let currentProcess = 'tiktok';
// 各专属区域
const configSection = document.getElementById('configSection');
const youtubeOnlySection = document.getElementById('youtubeOnlySection');
const urlConfigSection = document.getElementById('urlConfigSection');
const obsSection = document.getElementById('obsSection');
// youtube.ini 编辑youtube 专属)
const youtubeConfig = document.getElementById('youtubeConfig');
const loadConfigBtn = document.getElementById('loadConfigBtn');
const saveConfigBtn = document.getElementById('saveConfigBtn');
const configStatus = document.getElementById('configStatus');
const loadYoutubeBtn = document.getElementById('loadYoutubeBtn');
const saveYoutubeBtn = document.getElementById('saveYoutubeBtn');
const youtubeStatus = document.getElementById('youtubeStatus');
// URL_config.ini 编辑youtube 和 tiktok 共享)
const urlConfig = document.getElementById('urlConfig');
const loadUrlBtn = document.getElementById('loadUrlBtn');
const saveUrlBtn = document.getElementById('saveUrlBtn');
const urlStatus = document.getElementById('urlStatus');
processSelect.addEventListener('change', () => {
currentProcess = processSelect.value;
@@ -88,16 +115,81 @@ processSelect.addEventListener('change', () => {
updateSectionsVisibility();
});
// 根据当前进程显示/隐藏对应区域
function updateSectionsVisibility() {
configSection.style.display = currentProcess === 'youtube' ? 'block' : 'none';
youtubeOnlySection.style.display = currentProcess === 'youtube' ? 'block' : 'none';
urlConfigSection.style.display = (currentProcess === 'youtube' || currentProcess === 'tiktok') ? 'block' : 'none';
obsSection.style.display = currentProcess === 'obs' ? 'block' : 'none';
if (currentProcess === 'youtube') {
loadConfig();
loadYoutubeConfig();
}
if (currentProcess === 'youtube' || currentProcess === 'tiktok') {
loadUrlConfig();
}
}
// textarea 高度自适应
function autoResize(textarea) {
textarea.style.height = 'auto';
textarea.style.height = (textarea.scrollHeight) + 'px';
}
[youtubeConfig, urlConfig].forEach(ta => {
ta.addEventListener('input', () => autoResize(ta));
autoResize(ta);
});
// 通用加载/保存
async function loadConfig(endpoint, textarea, statusEl) {
statusEl.textContent = '加载中...';
try {
const res = await fetch(`${endpoint}?process=${currentProcess}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
textarea.value = data.content || '';
autoResize(textarea);
statusEl.textContent = '加载成功';
} catch (err) {
statusEl.textContent = `加载失败: ${err.message}`;
}
}
async function saveConfig(endpoint, textarea, statusEl, saveBtn) {
statusEl.textContent = '保存中...';
const content = textarea.value;
try {
const res = await fetch(`${endpoint}?process=${currentProcess}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({content})
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
statusEl.textContent = data.message || '保存成功';
} catch (err) {
statusEl.textContent = `保存失败: ${err.message}`;
} finally {
if (saveBtn) saveBtn.classList.remove('loading');
}
}
// youtube.ini仅 youtube
function loadYoutubeConfig() { loadConfig('/get_config', youtubeConfig, youtubeStatus); }
function saveYoutubeConfig() {
saveYoutubeBtn.classList.add('loading');
saveConfig('/save_config', youtubeConfig, youtubeStatus, saveYoutubeBtn);
}
loadYoutubeBtn.onclick = loadYoutubeConfig;
saveYoutubeBtn.onclick = saveYoutubeConfig;
// URL_config.iniyoutube 和 tiktok 共享)
function loadUrlConfig() { loadConfig('/get_url_config', urlConfig, urlStatus); }
function saveUrlConfig() {
saveUrlBtn.classList.add('loading');
saveConfig('/save_url_config', urlConfig, urlStatus, saveUrlBtn);
}
loadUrlBtn.onclick = loadUrlConfig;
saveUrlBtn.onclick = saveUrlConfig;
function scrollLog(){logEl.scrollTop = logEl.scrollHeight}
function updateStatus(process_status){
@@ -156,44 +248,6 @@ async function pm2Action(action){
async function fetchStatus(){ pm2Action('status'); }
// 配置加载
async function loadConfig(){
configStatus.textContent = '加载中...';
try{
const res = await fetch(`/get_config?process=${currentProcess}`);
if(!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
youtubeConfig.value = data.content || '';
configStatus.textContent = '加载成功';
}catch(err){
configStatus.textContent = `加载失败: ${err.message}`;
}
}
// 配置保存
async function saveConfig(){
configStatus.textContent = '保存中...';
const content = youtubeConfig.value;
try{
const res = await fetch(`/save_config?process=${currentProcess}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({content})
});
if(!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
configStatus.textContent = data.message || '保存成功';
}catch(err){
configStatus.textContent = `保存失败: ${err.message}`;
}
}
loadConfigBtn.onclick = loadConfig;
saveConfigBtn.onclick = () => {
saveConfigBtn.classList.add('loading');
saveConfig().finally(() => saveConfigBtn.classList.remove('loading'));
};
// 按钮事件委托
document.getElementById('pm2Buttons').addEventListener('click', e=>{
const btn = e.target.closest('button');
@@ -202,10 +256,8 @@ document.getElementById('pm2Buttons').addEventListener('click', e=>{
if(action && action !== 'status') pm2Action(action);
});
// 自动刷新状态与日志
// 自动刷新 + 初始
setInterval(fetchStatus, 1000);
// 初始加载
fetchStatus();
updateSectionsVisibility();
</script>