Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
173 commits
Select commit Hold shift + click to select a range
3fe15aa
Add Compress/Extract UI: context menus, templates, and dialog logic
mgutt Feb 8, 2026
8730ff6
Add Compress/Extract backend: Control.php and file_manager worker imp…
mgutt Feb 8, 2026
64869e6
Fix compress bugs: correct selector scope, add bulk compress toolbar …
mgutt Feb 8, 2026
f04dfe3
Fix compress parameter extraction: preserve format and archive_name a…
mgutt Feb 8, 2026
16e13b2
Fix compress: use escapeshellarg for basenames, support multiple sources
mgutt Feb 8, 2026
80ab6d7
Work in progress: improve compress progress display
mgutt Feb 22, 2026
fb9d538
Add zip progress tracking with parse_zip_progress() function
mgutt Mar 8, 2026
2b1eec7
Fix zip_wrapper and parse_zip_progress issues
mgutt Mar 8, 2026
d344618
Add debug logging to parse_zip_progress for troubleshooting
mgutt Mar 8, 2026
954c035
Add extensive debug logging to trace status check flow
mgutt Mar 8, 2026
0f293f0
Add debug logging around pid handling and cleanup
mgutt Mar 8, 2026
cffb522
Fix zip PID issue by removing pipeline
mgutt Mar 8, 2026
105cfd4
Add PID and process tree debug logging for zip progress tracking
mgutt Mar 8, 2026
5a245a8
Rewrite zip progress parser: incremental reading with total size calc…
mgutt Mar 8, 2026
06de83f
Add debug logging and remove obsolete zip_wrapper script
mgutt Mar 8, 2026
1f03598
Add debug logging to pid_exists and after switch statement
mgutt Mar 8, 2026
1f614d7
Fix PID tracking: redirect heredoc block to status file to keep shell…
mgutt Mar 8, 2026
e8d219c
Copy status file to /tmp before deletion for debugging compress progress
mgutt Mar 8, 2026
789f0c7
Auto-increment archive filename if target file already exists (TEST.z…
mgutt Mar 8, 2026
451545a
Simplify archive name auto-increment: check visible files instead of …
mgutt Mar 8, 2026
3cc6fb8
Fix zip progress: rewrite to line-by-line parsing with dot counting, …
mgutt Mar 8, 2026
1eb17cb
Revert to character-by-character parsing with individual DOT timestam…
mgutt Mar 8, 2026
cee92d6
Fix archive name: extract first source from multi-line text
mgutt Mar 8, 2026
8301e60
Use \r as source separator (consistent with backend)
mgutt Mar 8, 2026
bd2d8a1
Use static debug filename /tmp/status-debug-compress.txt for easier a…
mgutt Mar 8, 2026
698e456
Fix zip progress: use stdbuf -o0 to disable output buffering for char…
mgutt Mar 8, 2026
6e84bc5
Test: use >>status direct writes to check if buffering is the issue (…
mgutt Mar 8, 2026
8c11357
Fix regex syntax: remove unnecessary backslash in character class [^/]
mgutt Mar 8, 2026
c69a496
Fix zip regex for leading spaces, remove broken auto-increment (TODO:…
mgutt Mar 8, 2026
f003c47
Fix zip regex: remove $ anchor to match (size) immediately, not wait …
mgutt Mar 8, 2026
09eba73
Fix zip progress: check pattern after every char instead of only at n…
mgutt Mar 8, 2026
ec00239
Add INFO messages display to zip progress
mgutt Mar 8, 2026
28d1281
Refactor: unify FILE/DOT timestamps into progress_events array
mgutt Mar 8, 2026
a774da0
Fix: Show compress/extract progress in footer status bar
mgutt Mar 8, 2026
f9d178e
Fail if archive/rename target already exists; add TODO for extract ov…
mgutt Mar 8, 2026
b2616c5
Fix negative ETA when dot count exceeds du-reported size
mgutt Mar 8, 2026
24c461a
Refactor zip progress: replace avg-time heuristic with speed-based in…
mgutt Mar 8, 2026
2aaffd1
Optimize nchan traffic: skip publish when status unchanged
mgutt Mar 8, 2026
b27cb83
Add progress for tar formats using checkpoint+awk structured log
mgutt Mar 8, 2026
73477ac
Fix tar progress regression and archive name dropdown
mgutt Mar 8, 2026
55a4c8f
Unify compress progress: fixed 100MB/dot for both zip and tar
mgutt Mar 8, 2026
e59548b
Add tar.bz2 and tar.xz to compress format dropdown; move $pid init be…
mgutt Mar 22, 2026
6334a0d
Debug: add logging to extract case 17
mgutt Mar 22, 2026
b1c2edf
Hide tar.bz2 in compress dropdown (too unpopular)
mgutt Mar 22, 2026
9bcb37b
Fix extract: use >status redirect instead of tee to prevent exec() bl…
mgutt Mar 22, 2026
cfadc20
Fix extract: redirect stderr to error file so failures are surfaced t…
mgutt Mar 22, 2026
94725de
Add extract progress: structured FILE/DOT/TOTAL log format like compress
mgutt Mar 22, 2026
dce1150
Fix extract progress: unzip -n (no overwrite prompt), tar TOTAL pre-s…
mgutt Mar 22, 2026
ad78031
Fix extract ZIP progress: correct date regex MM-DD-YYYY for unzip -l …
mgutt Mar 22, 2026
d875b76
Fix extract ZIP progress: remove escaped quotes in assoc array assign…
mgutt Mar 22, 2026
8eca452
Fix extract ZIP progress: count files without leading spaces in TOTAL…
mgutt Mar 22, 2026
9899b98
Fix extract ZIP: remove unverified unzip keywords (linking, replacing…
mgutt Mar 22, 2026
7016bd7
Fix ZIP extract progress: parallel manifest-based poller instead of p…
mgutt Mar 22, 2026
5e78907
Fix ZIP extract: parallel arrays for manifest parser, ^J newline hand…
mgutt May 3, 2026
0637e18
Add Extract button to toolbar: enabled only when exactly one archive …
mgutt May 5, 2026
669a348
Fix doActions: calculate root/match for actions >=15 (fileTreeAttach …
mgutt May 5, 2026
69ae890
Fix Compress/Extract dialog: enable popular suggestion + filetree nav…
mgutt May 5, 2026
517fb21
Add overwrite checkbox to Extract dialog; use exist flag in all extra…
mgutt May 5, 2026
4601ff0
Fix ZIP extract: use PHP var for overwrite flag (HEREDOC does not eva…
mgutt May 5, 2026
21191e8
Fix TAR extract: use --skip-old-files instead of --keep-old-files (no…
mgutt May 5, 2026
e38537a
Fix TAR extract: suppress 'skipping existing file' warning with --war…
mgutt May 5, 2026
a65c780
Remove 7z extract support (7z binary not available on Unraid)
mgutt May 5, 2026
54f7f79
Remove rar extract support (unrar binary not available on Unraid)
mgutt May 5, 2026
5f8230e
Add tar.lz4 compress/extract support (lz4 available on Unraid)
mgutt May 5, 2026
941324f
feat: read docker paths from docker.cfg for compress format auto-dete…
mgutt May 5, 2026
6949959
fix: bulk compress used target dir instead of source dir as working d…
mgutt May 5, 2026
0444d92
fix: tar progress FILE lines now interleaved with DOT lines via stdbu…
mgutt May 5, 2026
8174f00
fix: tar progress FILE/DOT interleaving by using O_APPEND (>>) for bo…
mgutt May 5, 2026
725e0ee
fix: redirect group stdout to /dev/null so PHP exec() does not block …
mgutt May 5, 2026
b3ceb87
fix: remove stale archive_tmp reconstruction in status-check branch (…
mgutt May 5, 2026
2ddcf89
fix: use uniqid-based tmp path with collision-check loop, named targe…
mgutt May 5, 2026
ba7548e
cleanup: remove redundant stdbuf -oL (fflush() in awk already handles…
mgutt May 5, 2026
a2cb5c5
fix: tar extract progress - use correct compression flags for total_b…
mgutt May 5, 2026
c3a7a1a
fix: add missing archive_chown/archive_chmod variables for compress p…
mgutt May 5, 2026
079e586
fix: archive permissions docker-path detection now strips /mnt/<disk>…
mgutt May 6, 2026
1a40487
feat: enable tar.bz2 in compress UI; fix new-dir permissions for comp…
mgutt May 6, 2026
92e95b3
feat: track compress/extract target paths in popular destinations (ac…
mgutt May 6, 2026
93a3741
fix: single-source Queue handler missing case 16 - now includes forma…
mgutt May 6, 2026
4687b58
security: fix shell injection in compress/extract heredocs
mgutt May 6, 2026
97d2fe2
refactor: use isArchive() in context menu instead of inline ext list
mgutt May 6, 2026
f5b45ce
fix: strip all recognised archive extensions in updateArchiveName
mgutt May 6, 2026
563b5b6
security: prevent path traversal via archive_name
mgutt May 6, 2026
fbb9f21
fix: replace broken default format fallback with explicit error
mgutt May 6, 2026
f1eec18
fix: use sliding window for speed/ETA calculation
mgutt May 6, 2026
1235298
fix: simplify isArchive() to single regex; restrict to supported formats
mgutt May 6, 2026
e52813e
fix: apply allowed-root target validation to all compress submit paths
mgutt May 6, 2026
ef8b5fe
security: validate compress/extract target paths server-side
mgutt May 6, 2026
fc2b4bc
fix: archive_name empty/dot check; tar stderr to error file; ETA N/A …
mgutt May 6, 2026
6da3ec3
debug: trace archive_name through extract() and plugin_cfg restore
mgutt May 6, 2026
9fd4a3d
fix: tar --no-unquote for backslash in filenames; simplify tar_exit l…
mgutt May 6, 2026
997d978
debug: log full cmd, ret_code, process cmd for compress
mgutt May 6, 2026
eed5aa6
fix: unset tar_flags/cmd at loop top to prevent stale variable overri…
mgutt May 6, 2026
580e747
fix: show remaining file count in source list when more than 9 items …
mgutt May 6, 2026
0007f84
refactor: replace compress/extract heredocs with external progress sc…
mgutt May 6, 2026
477921a
fix: --no-unquote must precede -tvf in tar listing pass (was taken as…
mgutt May 6, 2026
273c91e
fix: unescape tar -tv filenames in listing pass (\n -> newline etc.)
mgutt May 6, 2026
80915ab
feat: async listing pass for tar extract (no 30s freeze at start)
mgutt May 6, 2026
99976b6
fix: set _prog_total before show_progress guard in _prog_total_line
mgutt May 6, 2026
48d7587
fix: crash when tar filename contains newline (keep escaped in manife…
mgutt May 6, 2026
a9d1332
feat: show speed in ETA line even before TOTAL is known
mgutt May 6, 2026
84d29b0
refactor: checkpoint-based progress for compressed tar extract (no li…
mgutt May 6, 2026
9d253cd
fix: add -v to compressed tar extract for filenames in progress
mgutt May 6, 2026
e68e8c8
fix: -v must be before -f in tar extract flags (not as separate arg)
mgutt May 6, 2026
4d0539d
refactor: clean up compress/extract command building
mgutt May 7, 2026
2bf20cb
progress: add short options, replace tar extract TOTAL logic
mgutt May 7, 2026
ef9278d
progress: clarify TOTAL is not guaranteed in header comment
mgutt May 7, 2026
8720208
progress: fix tar extract TOTAL emitted on timeout with partial sum
mgutt May 7, 2026
cd7dd8f
fix: download all archive types on click instead of opening viewer
mgutt May 7, 2026
7a22803
progress: support both ISO and US date formats in unzip -l output
mgutt May 7, 2026
4d9add6
fix: restore compress/extract dialog content after page navigation
mgutt May 7, 2026
9cb5d37
fix: republish last nchan status every 20s to prevent buffer timeout
mgutt May 7, 2026
b158780
progress: add stat-poller timeout and document unzip -^ requirement
mgutt May 7, 2026
13a9033
fix: use unzip -^ to preserve control chars in filenames during extract
mgutt May 7, 2026
47c534e
progress: fix unzip handling — char-by-char -f poll instead of manife…
mgutt May 7, 2026
bec0594
progress: unzip - trigger on space, exact manifest match, fix prefix …
mgutt May 7, 2026
aaba47f
progress: unzip - replace space-trigger with 100ms timeout dual-trigger
mgutt May 7, 2026
4cecf40
progress: unzip - fix dirs, stall guard, simplify; tar - fix newline …
mgutt May 7, 2026
2157439
progress: fix speed/ETA hidden, force 100% at done, add --progress flag
mgutt May 8, 2026
e7db13b
progress: use EPOCHREALTIME for sub-second CHUNK timestamps
mgutt May 8, 2026
0a0c372
file_manager: clear stale nchan state on new action start
mgutt May 8, 2026
7f09419
file_manager: fix zip symlinks and non-ASCII filenames
mgutt May 8, 2026
26fb786
fix: unzip manifest miss for UTF-8 filenames + locale hint
mgutt May 8, 2026
a1954c4
fix: progress script review feedback (4 items)
mgutt May 8, 2026
375926d
feat: compress overwrite option; fix dfm_read.source TypeError
mgutt May 8, 2026
dc69c53
feat: single-file compress formats (gz, xz, bz2, zst, lz4)
mgutt May 8, 2026
ac4d56d
fix: fallback for fast/small archives where process exits before pgre…
mgutt May 8, 2026
e79eb25
fix: single-file formats not filtered in bulk compress (doActions path)
mgutt May 8, 2026
9e69593
refactor: rename exist->overwrite with boolean semantics; fix bugs
mgutt May 8, 2026
9f56d60
fix: Extract button and backend support for single-file formats (.gz/…
mgutt May 8, 2026
ed11d64
fix: re-enable format and archive_name inputs on compress error
mgutt May 8, 2026
630d7a3
fix: context menu Extract item: read filename via dfm_proxy()
mgutt May 8, 2026
24586d4
security: validate source paths via validname() in compress and extract
mgutt May 8, 2026
83d9d65
feat: pv-based progress for tar.zst compress and extract
mgutt May 8, 2026
8d70cfc
debug: add logging for pv tar.zst compress/extract start and parse_pv…
mgutt May 8, 2026
b7ddf61
fix: add >/dev/null to pv group to prevent PHP exec() blocking
mgutt May 8, 2026
f5529f8
feat: extend pv progress to all tar variants and single-file formats
mgutt May 8, 2026
f182f4e
refactor: remove redundant $use_pv_compress, use isset($pv_compressor…
mgutt May 8, 2026
a5224a3
Add pv-zip progress for zip/unzip, extend pv to all tar variants
mgutt May 8, 2026
8514cff
throttle loop to 1s while pid active, remove progress script
mgutt May 8, 2026
281efd5
add copyright header to pv-zip
mgutt May 8, 2026
5e5e283
fix: restore archive_name+format in compress dialog after minimize/ma…
mgutt May 8, 2026
274d5a7
make fname_file optional last arg in pv-zip (was required 2nd arg)
mgutt May 8, 2026
7b33cbc
fix: unzip progress uses uncompressed sizes to avoid ETA explosion on…
mgutt May 8, 2026
d7b71c7
file_manager: use exit code to gate archive rename instead of error file
mgutt May 8, 2026
4b0937f
refactor: remove double JSON encoding in file_manager status replies
mgutt May 14, 2026
246ab02
add file_manager debug mode; rename pv-zip to pvzip; add integration …
mgutt May 14, 2026
07de81e
suppress output of empty json objects to filemanager nchan channel
mgutt May 14, 2026
cd8bd42
test: refactor test-file-manager.sh - run_action with single JSON tem…
mgutt May 14, 2026
cfb79bd
test: add create folder and delete test cases, keyword filter for tes…
mgutt May 14, 2026
52d602a
test: add rename and chmod test cases with special chars filenames
mgutt May 14, 2026
8c01bd8
test: add copy and move integration tests with fingerprint integrity …
mgutt May 14, 2026
2ec9ecd
debug: log generated rsync cmd to /var/tmp/fm_debug_cmd.txt in debug …
mgutt May 14, 2026
2767111
debug: display generated rsync cmd in test_move output
mgutt May 14, 2026
2f49197
debug: log target/cmd via syslog in move action start
mgutt May 14, 2026
3f8296c
debug: log full rsync includes in syslog
mgutt May 14, 2026
c534234
fix: restore dir mtimes after rsync-rename move
mgutt May 17, 2026
e402825
fix: clarify rsync_escape_component backslash escaping
mgutt May 17, 2026
fe51c6f
test: remove unconditional debug output from test_move
mgutt May 17, 2026
9826c62
test: refactor integrity checks - use find_metadata instead of tmp fi…
mgutt May 17, 2026
afdc140
fix zip symlink mtime; refactor debug logging; improve test script
mgutt May 17, 2026
bcf6e25
fix zip symlink mtime: add touch -m flag (set mtime only, not atime)
mgutt May 17, 2026
68014f0
test: add chown (action 11) and search (action 15) tests
mgutt May 17, 2026
9574adf
fix should_run(): normalize filter separators; use word-boundary matc…
mgutt May 17, 2026
af4630b
test: improve test_search with exact count and path validation
mgutt May 17, 2026
0bcbaa5
fix search: use find -print0 to handle filenames with newlines
mgutt May 17, 2026
7bc39b9
test: fix path check for filenames containing newlines
mgutt May 17, 2026
7bc92d2
test: only clean up dst files on success, skip on failure
mgutt May 17, 2026
4e8761b
test: extract src file creation into create_source_files function
mgutt May 17, 2026
2135344
test: restart file_manager before force-copy-delete tests
mgutt May 17, 2026
c601097
test: separate rename and move filters
mgutt May 17, 2026
e80cd58
test: split compress/extract filters, pre-build archives in create_so…
mgutt May 17, 2026
e0ea246
test: native archive building, fixed mtime, descriptive test labels
mgutt May 17, 2026
5867271
refactor: remove parse_compress_progress and unused constants
mgutt May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,297 changes: 1,297 additions & 0 deletions .github/scripts/test-file-manager.sh

Large diffs are not rendered by default.

229 changes: 216 additions & 13 deletions emhttp/plugins/dynamix/Browse.page

Large diffs are not rendered by default.

48 changes: 31 additions & 17 deletions emhttp/plugins/dynamix/BrowseButton.page
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const dfm = {
draggable: false,
previous: '',
height: 0,
tsize: {0: 0, 1: 6, 2: 3, 3: 3, 4: 3, 11: 2, 12: 2, 14: 0, 15: 3},
tsize: {0: 0, 1: 6, 2: 3, 3: 3, 4: 3, 11: 2, 12: 2, 14: 0, 15: 3, 16: 6, 17: 1},
};
var dfm_read = {};

Expand Down Expand Up @@ -136,7 +136,7 @@ function dfm_createSource(source) {
if (i < 10) {
$('<option></option>').text(object).prop('selected', i==0).appendTo(select);
} else {
select.append('<option>&lt;_(more)_&gt; ...</option>');
select.append('<option>(+' + (source.length - 9) + ' _(more)_)</option>');
break;
}
}
Expand All @@ -148,9 +148,8 @@ function dfm_createSource(source) {
function dfm_showProgress(data) {
if (!data) return 0;

// Try to parse as JSON first
try {
let parsed = JSON.parse(data);
let parsed = data;

// Handle search results (action 15 with results array)
if (parsed.action === 15 && Array.isArray(parsed.results)) {
Expand Down Expand Up @@ -237,9 +236,9 @@ function dfm_showProgress(data) {
}

// Build footer text (progress info only)
// Show footer for actions with actual progress: delete (1,6), copy (3,8), move (4,9), search (15)
// Show footer for actions with actual progress: delete (1,6), copy (3,8), move (4,9), search (15), compress (16), extract (17)
// No footer for quick operations: create (0), rename (2,7), chown (11), chmod (12)
let showFooter = [1, 3, 4, 6, 8, 9, 15].includes(parsed.action);
let showFooter = [1, 3, 4, 6, 8, 9, 15, 16, 17].includes(parsed.action);
if (showFooter) {
let footerText = parsed.text[1] || parsed.text[0] || '';
dfm_footer('write', footerText, $icon);
Expand All @@ -250,8 +249,7 @@ function dfm_showProgress(data) {

}
} catch(e) {
// Not JSON, log error
console.error('Failed to parse status as JSON:', e, data);
console.error('dfm_showProgress: unexpected data format', e, data);
return 0;
}
}
Expand Down Expand Up @@ -288,7 +286,9 @@ function dfm_makeDialog(open) {
}
dfm.window = $('#dfm_dialogWindow');
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
var dfm_source = dfm_read.source.split('\r').slice(0,9);
// Guard against dfm_read.source being undefined (e.g. mode:'read' returned empty data
// due to a timing race). filter(Boolean) removes empty strings from split results.
var dfm_source = (dfm_read.source || '').split('\r').filter(Boolean);
switch (dfm_read.action) {
case 0: // create folder/object
dfm.window.html($('#dfm_templateCreateFolder').html());
Expand All @@ -307,14 +307,14 @@ function dfm_makeDialog(open) {
dfm.window.html($('#dfm_templateCopyFolder').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.window.find('#dfm_overwrite').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 4: // move folder/object
dfm.window.html($('#dfm_templateMoveFolder').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.window.find('#dfm_overwrite').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 6: // delete file
Expand All @@ -325,14 +325,14 @@ function dfm_makeDialog(open) {
dfm.window.html($('#dfm_templateCopyFile').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.window.find('#dfm_overwrite').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 9: // move file
dfm.window.html($('#dfm_templateMoveFile').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true :false);
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
dfm.window.find('#dfm_overwrite').prop('checked',dfm_read.exist ? false : true);
dfm.height = 630;
break;
case 11: // change owner
Expand All @@ -354,13 +354,25 @@ function dfm_makeDialog(open) {
dfm.window.find('.dfm_text').html('').css({'line-height':'normal'});
dfm.height = 630;
break;
case 16: // compress
dfm.window.html($('#dfm_templateCompress').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.window.find('#dfm_format').val(dfm_read.format || 'zip').prop('disabled',true);
dfm.window.find('#dfm_archive_name').val(dfm_read.archive_name || '').prop('disabled',true);
dfm.height = 630;
break;
case 17: // extract
dfm.window.html($('#dfm_templateExtract').html());
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
dfm.height = 630;
break;
}
dfm.window.find('#dfm_source').attr('size',Math.min(dfm.tsize[dfm_read.action],dfm_source.length));
dfm_createSource(dfm_source);
dfm.window.find('#dfm_sparse').prop('disabled',true);
dfm.window.find('#dfm_exist').prop('disabled',true);
dfm.window.find('#dfm_overwrite').prop('disabled',true);
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
dfm.window.find('.dfm_overwrite').css({'opacity':'0.5'});
dfm.window.dialog({
classes: {'ui-dialog': 'ui-dfm'},
autoOpen: open || dfm.dialog,
Expand All @@ -378,7 +390,7 @@ function dfm_makeDialog(open) {
dfm.window.find('.dfm_text').html("_(Running)_...");
dfm_footer('hide');
dfm_fileManager('start');
$.post('/webGui/include/Control.php',{mode:'file',action:15,title:encodeURIComponent(dfm_read.title),source:encodeURIComponent(dfm_read.source),target:encodeURIComponent(dfm_target),hdlink:'',sparse:'',exist:'',zfs:''});
$.post('/webGui/include/Control.php',{mode:'file',action:15,title:encodeURIComponent(dfm_read.title),source:encodeURIComponent(dfm_read.source),target:encodeURIComponent(dfm_target),hdlink:'',sparse:'',overwrite:0,zfs:''});
} else {
return;
}
Expand Down Expand Up @@ -416,8 +428,10 @@ nchan_filemanager.on('message', function(msg) {
dfm_fileManager('stop');
dfm.window.find('.dfm_text').addClass('orange-text').css('white-space', 'pre-line').text(data.error);
dfm.window.find('#dfm_target').prop('disabled',false);
dfm.window.find('#dfm_format').prop('disabled',false);
dfm.window.find('#dfm_archive_name').prop('disabled',false);
dfm.window.find('#dfm_sparse').prop('disabled',false);
dfm.window.find('#dfm_exist').prop('disabled',false);
dfm.window.find('#dfm_overwrite').prop('disabled',false);
dfm.window.find('#dfm_owner').prop('disabled',false);
dfm.window.find('#dfm_group').prop('disabled',false);
dfm.window.find('#dfm_other').prop('disabled',false);
Expand Down
21 changes: 17 additions & 4 deletions emhttp/plugins/dynamix/include/Control.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
}

// Update popular destinations when dequeuing a job
if (in_array((int)($data['action'] ?? 0), [3, 4, 8, 9]) && !empty($data['target'] ?? '')) {
if (in_array((int)($data['action'] ?? 0), [3, 4, 8, 9, 16, 17]) && !empty($data['target'] ?? '')) {
updatePopularDestinations($data['target']);
}

Expand Down Expand Up @@ -241,19 +241,32 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
'target' => rawurldecode($_POST['target'] ?? ''),
'H' => empty($_POST['hdlink']) ? '' : 'H',
'sparse' => empty($_POST['sparse']) ? '' : '--sparse',
'exist' => empty($_POST['exist']) ? '--ignore-existing' : '',
'overwrite' => empty($_POST['overwrite']) ? 0 : 1,
'zfs' => rawurldecode($_POST['zfs'] ?? '')
];
// Add compress-specific parameters
if ($data['action'] === 16) {
$data['format'] = rawurldecode($_POST['format'] ?? 'zip');
$data['archive_name'] = rawurldecode($_POST['archive_name'] ?? '');
}
if (isset($_POST['task'])) {
// add task to queue
$data['task'] = rawurldecode($_POST['task']);
file_put_contents($jobs, json_encode($data)."\n", FILE_APPEND);
} else {
// start operation
// For cancel (action=99), preserve target_tmp from existing active JSON so
// the worker can clean up the partial compress tmp file
if ($data['action'] === 99 && file_exists($active)) {
$existing = json_decode(file_get_contents($active), true);
if (!empty($existing['target_tmp'])) {
$data['target_tmp'] = $existing['target_tmp'];
}
}
file_put_contents($active, json_encode($data));
// Update popular destinations only when an operation actually starts
// Action types: 3=copy folder, 4=move folder, 8=copy file, 9=move file
if (in_array((int)$data['action'], [3, 4, 8, 9]) && !empty($data['target'])) {
// Action types: 3=copy folder, 4=move folder, 8=copy file, 9=move file, 16=compress, 17=extract
if (in_array((int)$data['action'], [3, 4, 8, 9, 16, 17]) && !empty($data['target'])) {
updatePopularDestinations($data['target']);
}
}
Expand Down
96 changes: 78 additions & 18 deletions emhttp/plugins/dynamix/include/Templates.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_sparse">_(Use sparse option)_</span>
</label>
<label for="dfm_exist" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_exist">_(Overwrite existing files)_</span>
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>
Expand All @@ -91,9 +91,9 @@
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_sparse">_(Use sparse option)_</span>
</label>
<label for="dfm_exist" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_exist">_(Overwrite existing files)_</span>
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>
Expand Down Expand Up @@ -137,9 +137,9 @@
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_sparse">_(Use sparse option)_</span>
</label>
<label for="dfm_exist" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_exist">_(Overwrite existing files)_</span>
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>
Expand All @@ -161,9 +161,9 @@
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_sparse">_(Use sparse option)_</span>
</label>
<label for="dfm_exist" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_exist">_(Overwrite existing files)_</span>
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>
Expand Down Expand Up @@ -207,9 +207,9 @@
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_sparse">_(Use sparse option)_</span>
</label>
<label for="dfm_exist" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_exist">_(Overwrite existing files)_</span>
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>
Expand All @@ -231,9 +231,9 @@
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_sparse">_(Use sparse option)_</span>
</label>
<label for="dfm_exist" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_exist">_(Overwrite existing files)_</span>
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>
Expand Down Expand Up @@ -363,4 +363,64 @@ function getMode(file){
</script>
!-->
</div>

<div markdown="1" id="dfm_templateCompress">
_(Source)_:
: <span id="dfm_source"></span>

_(Archive format)_:
: <select id="dfm_format" onchange="updateArchiveName()">
<option value="zip">ZIP (_.zip_)</option>
<option value="tar">TAR (_.tar_)</option>
<option value="tar.gz">TAR.GZ (_.tar.gz_)</option>
<option value="tar.bz2">TAR.BZ2 (_.tar.bz2_)</option>
<option value="tar.xz">TAR.XZ (_.tar.xz_)</option>
<option value="tar.zst">TAR.ZST (_.tar.zst - recommended for appdata_)</option>
<option value="tar.lz4">TAR.LZ4 (_.tar.lz4_)</option>
<option value="gz" class="dfm_single_format">GZ (_.gz_)</option>
<option value="xz" class="dfm_single_format">XZ (_.xz_)</option>
<option value="bz2" class="dfm_single_format">BZ2 (_.bz2_)</option>
<option value="zst" class="dfm_single_format">ZST (_.zst_)</option>
<option value="lz4" class="dfm_single_format">LZ4 (_.lz4_)</option>
</select>

_(Archive name)_:
: <input type="text" id="dfm_archive_name" autocomplete="off" spellcheck="false" value="">

<wbr />
: <span class="flex flex-col gap-4">
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing archive)_</span>
</label>

<span class="dfm_text"></span>
</span>

<wbr />
: _(save to)_ ...

_(Target folder)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="HIDE_FILES_FILTER" data-pickmatch="" data-pickroot="" data-picktop="">
</div>

<div markdown="1" id="dfm_templateExtract">
_(Archive)_:
: <span id="dfm_source"></span>

<wbr />
: <span class="flex flex-col gap-4">
<label for="dfm_overwrite" class="inline-flex flex-wrap items-center gap-4">
<input type="checkbox" id="dfm_overwrite" value="" onchange="this.value=this.checked?'1':''">
<span class="dfm_overwrite">_(Overwrite existing files)_</span>
</label>
<span class="dfm_text"></span>
</span>

<wbr />
: _(extract to)_ ...

_(Target folder)_:
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="HIDE_FILES_FILTER" data-pickmatch="" data-pickroot="" data-picktop="">
</div>
</div>
Loading
Loading