(function () { var ctxMenu = document.getElementById('ctxMenu') var targetId = null var targetName = null function showCtx(x, y) { ctxMenu.style.left = x + 'px' ctxMenu.style.top = y + 'px' ctxMenu.hidden = false } function hideCtx() { ctxMenu.hidden = true; targetId = null; targetName = null } document.querySelectorAll('.adminFolder').forEach(function (card) { card.addEventListener('contextmenu', function (e) { e.preventDefault() targetId = card.getAttribute('data-folder-id') targetName = card.getAttribute('data-name') showCtx(e.clientX, e.clientY) }) }) document.addEventListener('click', function (e) { if (!ctxMenu.contains(e.target)) hideCtx() }) ctxMenu.addEventListener('click', function (e) { var btn = e.target.closest('button') if (!btn || !targetId) return var action = btn.getAttribute('data-action') if (action === 'rename') { var newName = window.prompt('새 폴더 이름', targetName) if (newName && newName !== targetName) { fetch('/op/folders/' + encodeURIComponent(targetId) + '/rename', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ newName: newName }) }).then(function (r) { return r.json() }).then(function (j) { if (j.ok) location.reload() else alert(j.message || '이름 변경 실패') }) } } else if (action === 'delete') { if (window.confirm('"' + targetName + '" 폴더를 정말 삭제할까요? 안의 영상이 모두 사라집니다.')) { fetch('/op/folders/' + encodeURIComponent(targetId) + '/delete', { method: 'POST' }).then(function (r) { return r.json() }).then(function (j) { if (j.ok) location.reload() else alert(j.message || '삭제 실패') }) } } hideCtx() }) // 폴더 추가 모달 var addBtn = document.getElementById('addFolderBtn') var modal = document.getElementById('addFolderModal') var input = document.getElementById('addFolderInput') var cancelBtn = document.getElementById('addFolderCancel') var confirmBtn = document.getElementById('addFolderConfirm') function openModal() { modal.hidden = false; input.value = ''; setTimeout(function () { input.focus() }, 0) } function closeModal() { modal.hidden = true } if (addBtn) { addBtn.addEventListener('click', openModal) cancelBtn.addEventListener('click', closeModal) modal.addEventListener('click', function (e) { if (e.target === modal) closeModal() }) input.addEventListener('keydown', function (e) { if (e.key === 'Enter') confirmBtn.click() }) confirmBtn.addEventListener('click', function () { var name = input.value.trim() if (!name) return fetch('/op/folders', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: name }) }).then(function (r) { return r.json() }).then(function (j) { if (j.ok) location.reload() else alert(j.message || '폴더 생성 실패') }) }) } // 도구 관리(ffmpeg / yt-dlp) function renderTool(name, tool) { var card = document.querySelector('.toolCard[data-tool="' + name + '"]') if (!card) return var versionEl = card.querySelector('[data-field="version"]') var pathEl = card.querySelector('[data-field="path"]') if (!tool || !tool.available) { versionEl.textContent = '설치되지 않음' pathEl.textContent = '' return } versionEl.textContent = (tool.version || '버전 미상') + (tool.managed ? ' · 직접 설치본' : '') pathEl.textContent = tool.path || '' } function loadTools() { fetch('/op/tools').then(function (r) { return r.json() }).then(function (j) { if (!j.ok) return renderTool('yt-dlp', j.tools.ytDlp) renderTool('ffmpeg', j.tools.ffmpeg) }).catch(function () {}) } document.querySelectorAll('[data-action="update-tool"]').forEach(function (btn) { btn.addEventListener('click', function () { var name = btn.getAttribute('data-name') var card = btn.closest('.toolCard') var statusEl = card.querySelector('[data-field="status"]') btn.disabled = true statusEl.textContent = '재설치 중… (수십 초 걸릴 수 있습니다)' fetch('/op/tools/' + encodeURIComponent(name) + '/update', { method: 'POST' }) .then(function (r) { return r.json() }) .then(function (j) { if (j.ok) { statusEl.textContent = '완료' renderTool(name, j.tool) } else { statusEl.textContent = '실패: ' + (j.message || '알 수 없는 오류') } }) .catch(function (err) { statusEl.textContent = '실패: ' + (err && err.message ? err.message : '요청 오류') }) .then(function () { btn.disabled = false }) }) }) if (document.querySelector('.toolsSection')) loadTools() })()