diff options
| -rw-r--r-- | layouts/recordings/recordings-plain.html | 140 | ||||
| -rw-r--r-- | static/api/leak-files.php | 42 | ||||
| -rw-r--r-- | static/api/whoami.php | 11 |
3 files changed, 191 insertions, 2 deletions
diff --git a/layouts/recordings/recordings-plain.html b/layouts/recordings/recordings-plain.html index a36964d..d3c273e 100644 --- a/layouts/recordings/recordings-plain.html +++ b/layouts/recordings/recordings-plain.html @@ -232,6 +232,20 @@ {{ end }} {{ $folderGroups := $.Scratch.Get "folderGroups" }} + {{/* Leak 폴더가 없으면 강제로 추가 (파일이 없어도 표시) */}} + {{ $leakLower := "leak" }} + {{ $hasLeak := false }} + {{ range $folderName, $exists := $folderGroups }} + {{ if eq (lower $folderName) $leakLower }} + {{ $hasLeak = true }} + {{ end }} + {{ end }} + {{ if not $hasLeak }} + {{ $folderGroups = merge $folderGroups (dict "Leak" true) }} + {{ $.Scratch.Set "folderGroups" $folderGroups }} + {{ $.Scratch.Set "folder_Leak" (slice) }} + {{ end }} + {{ $folderGroups = $.Scratch.Get "folderGroups" }} {{ range $folderName, $exists := $folderGroups }} {{ $files := $.Scratch.Get (printf "folder_%s" $folderName) }} {{ $isRestricted := or (eq $folderName "hidden") (eq (lower $folderName) "leak") }} @@ -421,6 +435,132 @@ } }); + // Leak 폴더의 동영상 파일 목록 자동 로드 (에러 발생해도 다른 기능에 영향 없음) + (function() { + const loadLeakFiles = async () => { + try { + // si 사용자인지 확인 + let isSiUser = false; + try { + const cookies = document.cookie.split(';').reduce((acc, cookie) => { + const [key, value] = cookie.trim().split('='); + acc[key] = value; + return acc; + }, {}); + isSiUser = cookies.user === 'si' || cookies.authUser === 'si'; + + if (!isSiUser) { + const response = await fetch('/api/whoami.php', { credentials: 'include' }); + if (response.ok) { + const data = await response.json(); + isSiUser = data && data.user === 'si'; + } + } + } catch (e) { + // whoami 실패해도 무시 + return; + } + + if (!isSiUser) return; // si 사용자가 아니면 Leak 파일 로드 안 함 + + // Leak 섹션 찾기 (allowed 클래스가 있는 것만) + const findLeakSection = () => { + try { + return Array.from(document.querySelectorAll('li.folder-section[data-restricted="true"].allowed')) + .find(li => { + const folderName = li.querySelector('.folder-name'); + if (!folderName) return false; + const name = folderName.textContent.toLowerCase(); + return name.includes('leak'); + }); + } catch (e) { + return null; + } + }; + + // allowed 클래스가 추가될 때까지 대기 + let leakSection = findLeakSection(); + if (!leakSection) { + setTimeout(() => { + try { + leakSection = findLeakSection(); + if (leakSection) { + loadFilesIntoSection(leakSection); + } + } catch (e) { + // 에러 무시 + } + }, 500); + return; + } + + loadFilesIntoSection(leakSection); + + async function loadFilesIntoSection(leakSection) { + try { + const folderContent = leakSection.querySelector('.folder-content'); + if (!folderContent) return; + + const response = await fetch('/api/leak-files.php', { credentials: 'include' }); + if (!response.ok) return; // 404 등 에러는 무시 + + const data = await response.json(); + if (!data || !data.files || !Array.isArray(data.files)) return; + + const existingFiles = new Set(Array.from(folderContent.querySelectorAll('a')).map(a => a.textContent.trim())); + + let addedCount = 0; + data.files.forEach(file => { + if (file && file.name && !existingFiles.has(file.name)) { + try { + const li = document.createElement('li'); + const a = document.createElement('a'); + a.href = file.url || ('/recordings/Leak/' + encodeURIComponent(file.name)); + a.textContent = file.name; + a.className = 'hidden-file'; + a.setAttribute('data-name', file.name); + + const badge = document.createElement('span'); + badge.className = 'badge'; + badge.textContent = 'video'; + + li.appendChild(a); + li.appendChild(badge); + folderContent.appendChild(li); + addedCount++; + } catch (e) { + // 개별 파일 추가 실패해도 무시 + } + } + }); + + // 폴더 카운트 업데이트 + if (addedCount > 0) { + const countEl = leakSection.querySelector('.folder-count'); + if (countEl) { + const currentCount = parseInt(countEl.textContent.match(/\d+/)?.[0] || '0'); + countEl.textContent = `(${currentCount + addedCount} items)`; + } + } + } catch (e) { + // API 에러 무시 + } + } + } catch (e) { + // 모든 에러 무시 (다른 기능에 영향 없음) + } + }; + + // 사용자 확인 후 Leak 파일 로드 (약간 지연) + setTimeout(() => { + try { + loadLeakFiles(); + } catch (e) { + // 에러 무시 + } + }, 1000); + })(); + // 같은 날짜 내에서 폴더명 역순 정렬 const listEl = document.getElementById('list'); if (listEl) { diff --git a/static/api/leak-files.php b/static/api/leak-files.php new file mode 100644 index 0000000..cd0a104 --- /dev/null +++ b/static/api/leak-files.php @@ -0,0 +1,42 @@ +<?php +// Return list of video files in Leak folder +header('Content-Type: application/json'); +header('Access-Control-Allow-Origin: *'); +header('Access-Control-Allow-Credentials: true'); + +$leakDir = '/var/www/thesiah/recordings/Leak'; +$files = []; + +try { + if (is_dir($leakDir) && is_readable($leakDir)) { + $items = scandir($leakDir); + if ($items !== false) { + foreach ($items as $item) { + if ($item === '.' || $item === '..') continue; + $path = $leakDir . '/' . $item; + if (is_file($path) && is_readable($path)) { + $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION)); + if (in_array($ext, ['mp4', 'mov', 'avi', 'mkv', 'webm'])) { + $files[] = [ + 'name' => $item, + 'url' => '/recordings/Leak/' . urlencode($item), + 'size' => filesize($path), + 'modified' => filemtime($path) + ]; + } + } + } + // 최신 파일부터 정렬 + usort($files, function($a, $b) { + return $b['modified'] - $a['modified']; + }); + } + } +} catch (Exception $e) { + // 에러 발생 시 빈 배열 반환 + $files = []; +} + +echo json_encode(['files' => $files]); +?> + diff --git a/static/api/whoami.php b/static/api/whoami.php index f32cd2c..18a66f2 100644 --- a/static/api/whoami.php +++ b/static/api/whoami.php @@ -4,8 +4,15 @@ header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Credentials: true'); -// nginx에서 전달된 사용자 정보 읽기 (X-Auth-User 헤더 또는 REMOTE_USER) -$user = $_SERVER['HTTP_X_AUTH_USER'] ?? $_SERVER['REMOTE_USER'] ?? ''; +// nginx에서 전달된 사용자 정보 읽기 (쿠키 우선, 그 다음 헤더, 마지막으로 REMOTE_USER) +$user = ''; +if (isset($_COOKIE['user']) && $_COOKIE['user']) { + $user = $_COOKIE['user']; +} elseif (isset($_SERVER['HTTP_X_AUTH_USER']) && $_SERVER['HTTP_X_AUTH_USER']) { + $user = $_SERVER['HTTP_X_AUTH_USER']; +} elseif (isset($_SERVER['REMOTE_USER']) && $_SERVER['REMOTE_USER']) { + $user = $_SERVER['REMOTE_USER']; +} echo json_encode(['user' => $user]); ?> |
