From f5ca8c3eb5d6e8da2c4bcb220e07ef0ee8edf138 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?=
Date: Wed, 19 Aug 2026 18:41:43 +0400
Subject: [PATCH] =?UTF-8?q?Revert=20"v0.0.47:=20=D0=B2=D1=8B=D0=B1=D0=BE?=
=?UTF-8?q?=D1=80=20=D1=86=D0=B5=D0=BB=D0=BE=D0=B9=20=D0=BF=D0=B0=D0=BF?=
=?UTF-8?q?=D0=BA=D0=B8=20(webkitdirectory)=20=E2=80=94=20=D1=80=D0=B5?=
=?UTF-8?q?=D0=BA=D1=83=D1=80=D1=81=D0=B8=D0=B2=D0=BD=D0=BE,=20=D0=BA?=
=?UTF-8?q?=D0=B0=D0=BA=20=D1=80=D0=B0=D1=81=D0=BA=D1=80=D1=8B=D1=82=D0=B8?=
=?UTF-8?q?=D0=B5=20ZIP"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit b5a14cfc3d970285022d189630128905c9b69d88.
---
History/2026-08-19-folder-select-recursive.md | 45 -------------------
site/app.py | 2 +-
site/templates/index.html | 36 +--------------
3 files changed, 2 insertions(+), 81 deletions(-)
delete mode 100644 History/2026-08-19-folder-select-recursive.md
diff --git a/History/2026-08-19-folder-select-recursive.md b/History/2026-08-19-folder-select-recursive.md
deleted file mode 100644
index 0f7b020..0000000
--- a/History/2026-08-19-folder-select-recursive.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# v0.0.47 — Выбор целой папки (рекурсивно, как раскрытие ZIP) — 2026-08-19
-
-## Проблема
-Нативный `` (`site/templates/index.html:133`) не умеет выбирать
-папку целиком: клик по папке просто «входит» внутрь. Нужно выбирать целую папку
-и рекурсивно забирать все файлы — как при раскрытии архива.
-
-## Решение
-- Второй `` + кнопка
- «📁 Выбрать папку» (вызов `folderInput.click()`).
- `webkitdirectory` взаимоисключающ с обычным выбором файлов на одном input —
- поэтому отдельный input, а не переключатель.
-- Браузер сам отдаёт ВСЕ файлы папки рекурсивно (включая подпапки) с полем
- `file.webkitRelativePath`. Имя добавляемого файла = `webkitRelativePath`
- (структура папок сохраняется до итогового ZIP, как у архива сохраняется
- внутренний `e.name`).
-- Обработка — та же логика, что у раскрытия ZIP (`listZipFiles`):
- - `.zip` → рекурсивное раскрытие (вложенные zip тоже);
- - документы `.pdf .doc .docx .txt .md` → в таблицу;
- - прочее (картинки и т.п.) → пропускается.
-- Сортировка входящих файлов по `webkitRelativePath` — детерминированный порядок.
-
-## Файлы
-- `site/templates/index.html`
- - CSS: `.folder-btn` (полная ширина), `#folderInput { display:none }`
- - HTML: скрытый `#folderInput` + кнопка в `.file-input-wrap`
- - JS: `const folderInput`, обработчик `change` (рекурсия+фильтр+имена с путями)
- - `resetAll()` и `load` — сброс `folderInput.value`
-- `site/app.py` — VERSION 0.0.46 → 0.0.47
-
-## Бэкенд — не менялся
-- `extract_text` (drhider/extractor.py:204) берёт расширение через
- `os.path.splitext` — пути в имени не мешают.
-- `build_zip` (drhider/builder.py) пишет `ZipInfo` с путями как есть;
- `_resolve_name` дедуплицирует по полному имени — одноимённые файлы в разных
- подпапках не сталкиваются.
-- Аплоад идёт из массива `sf` (`uploadFiles`), а не из `fi.files` — файлы из
- папки уходят на бэк обычным путём.
-
-## Проверка
-1. «Выбрать папку» → папка с подпапками, вложенными .zip и картинками →
- в таблице только документы, рекурсивно; .zip раскрыт; картинки пропущены;
- имена с путями.
-2. Обфускация → скачать ZIP → вложенность папок сохранена, всё обфусцировано.
-3. Регрессия: обычный «Выбрать файлы» работает как раньше.
diff --git a/site/app.py b/site/app.py
index 6e72dc4..8523028 100644
--- a/site/app.py
+++ b/site/app.py
@@ -20,7 +20,7 @@ if _sys_path_root not in sys.path:
sys.path.insert(0, _sys_path_root)
# Версия приложения (меняется при изменениях)
-VERSION = "0.0.47"
+VERSION = "0.0.46"
def create_app():
diff --git a/site/templates/index.html b/site/templates/index.html
index a59d98e..1aa780e 100644
--- a/site/templates/index.html
+++ b/site/templates/index.html
@@ -44,8 +44,6 @@
.sub { font-size: 12px; color: var(--muted); margin-bottom: 10px; line-height: 1.5; }
.file-input-wrap { margin-bottom: 10px; }
.file-input-wrap input[type="file"] { width: 100%; font-size: 13px; }
- .folder-btn { margin-top: 6px; width: 100%; }
- #folderInput { display: none; }
.table-wrap { border: 1px solid var(--brand-gray); border-radius: 8px; overflow: hidden; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
@@ -133,8 +131,6 @@
-
-
@@ -192,7 +188,6 @@ const fl = document.getElementById('fileList');
const fc = document.getElementById('fileCount');
const ub = document.getElementById('uploadBtn');
const st = document.getElementById('status');
-const folderInput = document.getElementById('folderInput');
const db = document.getElementById('dlBtns');
let sf = [];
let fileMeta = new Map(); // имя -> {size, mtime} для дедупа/суффиксов
@@ -207,7 +202,6 @@ function resetAll() {
sf = [];
fileMeta = new Map();
fi.value = '';
- folderInput.value = '';
rr();
st.className = '';
st.textContent = '';
@@ -231,7 +225,7 @@ function rr() {
function rm(i) { fileMeta.delete(sf[i].name); sf.splice(i, 1); const d = new DataTransfer(); sf.forEach(f => d.items.add(f)); fi.files = d.files; rr(); }
-window.addEventListener('load', () => { sf = []; fileMeta = new Map(); fi.value = ''; folderInput.value = ''; rr(); /* прогрев upstream-соединения */ fetch('/health').catch(() => {}); });
+window.addEventListener('load', () => { sf = []; fileMeta = new Map(); fi.value = ''; rr(); /* прогрев upstream-соединения */ fetch('/health').catch(() => {}); });
// ═══════════ Нативная распаковка ZIP (без внешних библиотек) ═══════════
function dosToMs(date, time) {
@@ -367,34 +361,6 @@ fi.addEventListener('change', async () => {
rr();
});
-// ═══ Выбор целой папки: рекурсивно, как раскрытие ZIP ═══
-// webkitdirectory отдаёт все файлы папки (включая подпапки) с webkitRelativePath.
-folderInput.addEventListener('change', async () => {
- const docExts = ['.pdf', '.doc', '.docx', '.txt', '.md'];
- const incoming = Array.from(folderInput.files).sort((a, b) =>
- (a.webkitRelativePath || a.name).localeCompare(b.webkitRelativePath || b.name));
- for (const f of incoming) {
- const rel = f.webkitRelativePath || f.name; // сохраняем структуру папок
- const low = rel.toLowerCase();
- if (low.endsWith('.zip')) {
- try {
- const nested = await listZipFiles(new File([f], rel, { lastModified: f.lastModified }));
- nested.forEach(x => addFileWithDedup(x));
- } catch (err) {
- addFileWithDedup(new File([f], rel, { lastModified: f.lastModified })); // не удалось — добавить как есть
- }
- } else if (docExts.some(ext => low.endsWith(ext))) {
- addFileWithDedup(new File([f], rel, { lastModified: f.lastModified }));
- }
- // иначе — не документ, пропускаем
- }
- const d = new DataTransfer();
- sf.forEach(f => d.items.add(f));
- fi.files = d.files;
- folderInput.files = d.files;
- rr();
-});
-
function ss(idx, h) { const e = document.getElementById('st-' + idx); if (e) e.innerHTML = h; }
async function uploadFiles() {