diff --git a/build-plugin.sh b/build-plugin.sh
index 441e3fe..da35fd4 100755
--- a/build-plugin.sh
+++ b/build-plugin.sh
@@ -2,7 +2,7 @@
set -eu
PLUGIN="u-navigator"
-VERSION="2026.06.23.r045"
+VERSION="2026.06.23.r046"
PKG_DIR="packages"
WORK_DIR=".plugin-build"
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
diff --git a/packages/u-navigator-2026.06.23.r045.tgz b/packages/u-navigator-2026.06.23.r045.tgz
deleted file mode 100644
index 0067e32..0000000
Binary files a/packages/u-navigator-2026.06.23.r045.tgz and /dev/null differ
diff --git a/packages/u-navigator-2026.06.23.r046.tgz b/packages/u-navigator-2026.06.23.r046.tgz
new file mode 100644
index 0000000..3fd68bc
Binary files /dev/null and b/packages/u-navigator-2026.06.23.r046.tgz differ
diff --git a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php
index 5001cbb..fe60f78 100644
--- a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php
+++ b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php
@@ -7,6 +7,31 @@ if (!is_dir($target['path'])) {
unav_error(400, 'Upload target must be a directory');
}
+if (isset($_GET['relativePath']) || isset($_SERVER['HTTP_X_UNAV_RELATIVE_PATH'])) {
+ $relativeName = (string)($_GET['relativePath'] ?? $_SERVER['HTTP_X_UNAV_RELATIVE_PATH']);
+ $destination = unav_prepare_upload_destination($target['path'], $relativeName);
+ $input = fopen('php://input', 'rb');
+ $output = fopen($destination['path'], 'xb');
+ if (!$input || !$output) {
+ if ($input) {
+ fclose($input);
+ }
+ if ($output) {
+ fclose($output);
+ }
+ unav_error(500, 'Could not open upload stream');
+ }
+ stream_copy_to_stream($input, $output);
+ fclose($input);
+ fclose($output);
+ unav_json([
+ 'uploaded' => [[
+ 'name' => $destination['relative'],
+ 'size' => filesize($destination['path']) ?: 0,
+ ]],
+ ], 201);
+}
+
$uploaded = [];
$names = unav_upload_array($_FILES['files']['name'] ?? []);
$errors = unav_upload_array($_FILES['files']['error'] ?? []);
@@ -17,33 +42,38 @@ foreach ($names as $index => $name) {
unav_error(400, 'Upload failed');
}
$relativeName = $relativePaths[$index] ?? $name;
- $safeName = unav_upload_safe_relative_path((string)$relativeName);
+ $destination = unav_prepare_upload_destination($target['path'], (string)$relativeName);
+ if (!move_uploaded_file($tmpNames[$index] ?? '', $destination['path'])) {
+ unav_error(500, 'Could not store uploaded file');
+ }
+ $uploaded[] = [
+ 'name' => $destination['relative'],
+ 'size' => filesize($destination['path']) ?: 0,
+ ];
+}
+
+unav_json(['uploaded' => $uploaded], 201);
+
+function unav_prepare_upload_destination(string $targetPath, string $relativeName): array {
+ $safeName = unav_upload_safe_relative_path($relativeName);
$relativeParent = dirname($safeName);
if ($relativeParent !== '.') {
- $parentCandidate = $target['path'] . '/' . $relativeParent;
- unav_root_for_real($target['path']);
+ $parentCandidate = $targetPath . '/' . $relativeParent;
+ unav_root_for_real($targetPath);
if (!is_dir($parentCandidate) && !mkdir($parentCandidate, 0777, true) && !is_dir($parentCandidate)) {
unav_error(500, 'Could not create upload directory');
}
}
- $destination = unav_destination_path($target['path'] . '/' . $safeName);
+ $destination = unav_destination_path($targetPath . '/' . $safeName);
if (file_exists($destination['path'])) {
unav_error(409, 'Destination already exists');
}
if (!is_dir(dirname($destination['path']))) {
unav_error(500, 'Could not create upload directory');
}
- if (!move_uploaded_file($tmpNames[$index] ?? '', $destination['path'])) {
- unav_error(500, 'Could not store uploaded file');
- }
- $uploaded[] = [
- 'name' => $safeName,
- 'size' => filesize($destination['path']) ?: 0,
- ];
+ return ['path' => $destination['path'], 'relative' => $safeName];
}
-unav_json(['uploaded' => $uploaded], 201);
-
function unav_upload_array($value): array {
if (is_array($value)) {
return array_values($value);
diff --git a/server/public/app.js b/server/public/app.js
index 01deee2..5cfd2e0 100644
--- a/server/public/app.js
+++ b/server/public/app.js
@@ -904,13 +904,21 @@ async function uploadFileList(win, files, targetPath) {
const uploadItems = normalizeUploadItems(files);
for (const [index, item] of uploadItems.entries()) {
recordDebug('upload.file.request', { path: item.path, size: item.file.size, index: index + 1, total: uploadItems.length });
- const form = new FormData();
- form.append('files', item.file, item.file.name);
- form.append('relativePath', item.path);
- appendCsrf(form);
- await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), {
+ const params = new URLSearchParams({
+ path: targetPath,
+ relativePath: item.path
+ });
+ const token = getCsrfToken();
+ if (token) {
+ params.set('csrf_token', token);
+ recordDebug('csrf.attached', { length: token.length });
+ } else {
+ recordDebug('csrf.missing', {});
+ }
+ await fetchChecked(apiUrl(`upload.php?${params.toString()}`), {
method: 'POST',
- body: form
+ headers: { 'Content-Type': 'application/octet-stream' },
+ body: item.file
});
recordDebug('upload.file.done', { path: item.path, index: index + 1, total: uploadItems.length });
}
diff --git a/u-navigator.plg b/u-navigator.plg
index aa0e035..030e657 100644
--- a/u-navigator.plg
+++ b/u-navigator.plg
@@ -1,7 +1,7 @@
-
+
@@ -24,7 +24,7 @@
https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;
-cd3b5a92d7174924985b5d929cb180fe
+acb81bdc26294c48b2115013cac89015