mirror of
https://github.com/LisherSong/ps5-web-file-manager.git
synced 2026-10-06 06:00:23 +02:00
Show extract button for RAR (single + multi-volume) archives
User reported FTP-upload-and-extract use case: after uploading .part01.rar..part05.rar via FTP, the extract button should appear on selection just like .zip already does, alongside the existing delete / copy / move / rename buttons in the toolbar. Changes are purely client-side. The extractBtn sits next to deleteBtn in the toolbar (HTML layout unchanged). New helpers: - isRarMainVolume(item): matches bare .rar AND .part01.rar/.part1.rar / .part001.rar, but excludes any .partNN.rar (those are sub-volumes) - isRarSubVolume(item): matches .part02+.rar (the non-first parts) - isExtractableArchive(item): .zip OR rar main volume renderExtractButton rewiring: - archives.length + subs.length both zero -> hidden (unchanged default) - only subs selected -> button visible but disabled with tooltip 'select the main volume (.rar or .part01.rar)' (new i18n keys) - exactly one archive selected -> button enabled with hover target actionExtract wired to the new isExtractableArchive filter, keeping the existing 'must be exactly 1 selected' guard so multi-select still no-ops cleanly. Caught a real bug while wiring: the first version of isRarMainVolume matched /\.rar$/ before the part01 check, so part02+ was incorrectly classified as a main volume. Fixed by reordering + adding negative sub-pattern so .partNN. never trips the bare-.rar rule. Two new i18n keys (zh + en): - extractSelectMainVolume: friendly message when user picks only sub-volumes - extractArchivePending: reserved for the future RAR password prompt 10/10 unit cases pass for the detection regexes (zip / .rar / .part01.rar / .part02.rar / .tar.gz / .bin). Backend support for RAR is not part of this commit; clicking Extract on a .rar on v1.7 still returns err_extract_unsupported from the existing zip_extract pipeline. That will swap to the unrar engine in v1.8 without any further frontend work. Also sets local repo core.autocrlf=false to keep JS files LF on this Windows dev machine (global autocrlf was rewriting them as CRLF on write and causing the whole file to show up as changed on every edit).
This commit is contained in:
1 parent
c7d9e965b8
commit
bfe522e56b
3 files changed
+49
-7
No files matched your search
@@ -107,6 +107,8 @@ window.WFM_LANG = {
|
||||
extractProgress: "{done} / {total} files",
|
||||
extractLargeAsk: "The archive looks large ({size}). Enable the large-file profile?\n\nOK = yes (single file up to 1 TiB, archive total up to 2 TiB)\nCancel = default limits (single file 64 GiB, archive total 512 GiB); this archive may be rejected",
|
||||
extractLargeActive: "Large-file profile is enabled for this task",
|
||||
extractSelectMainVolume: "Please select the main volume (.rar or .part01.rar)",
|
||||
extractArchivePending: "Preparing to extract {name}",
|
||||
sameSourceTarget: "Source and destination are the same. Cannot {label} {name}",
|
||||
removeConflictFirst: "A {existingType} named {name} already exists. To {label} this {sourceType}, delete that {existingType} first.",
|
||||
overwriteFiles: "Files with the same name will be overwritten: {names}",
|
||||
|
||||
@@ -107,6 +107,8 @@ window.WFM_LANG = {
|
||||
extractProgress: "{done} / {total} 个文件",
|
||||
extractLargeAsk: "ZIP 体积较大({size}),是否启用「大文件模式」?\n\n确定 = 启用(单文件最大 1 TiB / 总解压最大 2 TiB)\n取消 = 默认限制(单文件 64 GiB / 总解压 512 GiB),可能拒绝此压缩包",
|
||||
extractLargeActive: "此任务已启用大文件模式",
|
||||
extractSelectMainVolume: "请改选主卷(如 .rar 或 .part01.rar)",
|
||||
extractArchivePending: "正在准备解压 {name}",
|
||||
sameSourceTarget: "源和目标相同,不能{label} {name}",
|
||||
removeConflictFirst: "目标中已存在同名{existingType} {name}。要{label}{sourceType},请先删除该{existingType}才能继续。",
|
||||
overwriteFiles: "同名文件将被覆盖: {names}",
|
||||
|
||||
+45
-7
@@ -746,6 +746,31 @@ function isZipArchive(item) {
|
||||
return item.type === "-" && /\.zip$/i.test(item.name);
|
||||
}
|
||||
|
||||
function isRarMainVolume(item) {
|
||||
if (item.type !== "-") return false;
|
||||
const name = item.name;
|
||||
// RAR5 分卷首卷(数字最小的那一卷):name.part01.rar / name.part1.rar / name.part001.rar
|
||||
if (/\.part0*1\.rar$/i.test(name)) return true;
|
||||
// 真正的单卷 .rar —— 排除任何包含 .partNN. 的文件名
|
||||
if (/\.rar$/i.test(name) && !/\.part0*\d+\./i.test(name)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isRarSubVolume(item) {
|
||||
if (item.type !== "-") return false;
|
||||
// RAR5 非首卷:.part02.rar, .part2.rar, .part002.rar ...
|
||||
if (/\.part0*\d+\.rar$/i.test(item.name) &&
|
||||
!/\.part0*1\.rar$/i.test(item.name)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isExtractableArchive(item) {
|
||||
if (item.type !== "-") return false;
|
||||
if (/\.zip$/i.test(item.name)) return true;
|
||||
if (isRarMainVolume(item)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isSpecialDirectory(item) {
|
||||
if (item.type !== "d") return false;
|
||||
if (item.path === "/data") return true;
|
||||
@@ -822,9 +847,9 @@ function promptLargeMode(sizeBytes) {
|
||||
|
||||
function actionExtract() {
|
||||
if (busy || loadingPath) return;
|
||||
const zips = selectedEntries().filter(isZipArchive);
|
||||
if (zips.length !== 1) return;
|
||||
const item = zips[0];
|
||||
const archives = selectedEntries().filter(isExtractableArchive);
|
||||
if (archives.length !== 1) return;
|
||||
const item = archives[0];
|
||||
if (!confirm(t("extractConfirm", { name: displayName(item), path: displayPath(cwd) }))) return;
|
||||
const conflict = confirm(t("extractOverwriteAsk")) ? "overwrite" : "fail";
|
||||
const large = shouldPromptLargeMode(item.size) ? promptLargeMode(item.size) : false;
|
||||
@@ -1327,14 +1352,27 @@ function renderInstallPkgButton(items, locked) {
|
||||
}
|
||||
|
||||
function renderExtractButton(items, locked) {
|
||||
const zips = items.filter(isZipArchive);
|
||||
extractBtn.hidden = zips.length !== 1;
|
||||
if (zips.length !== 1) {
|
||||
const archives = items.filter(isExtractableArchive);
|
||||
const subs = items.filter(isRarSubVolume);
|
||||
|
||||
// 没有可解压档案也没有子卷 → 隐藏按钮
|
||||
if (archives.length === 0 && subs.length === 0) {
|
||||
extractBtn.hidden = true;
|
||||
extractBtn.title = "";
|
||||
extractBtn.disabled = true;
|
||||
return;
|
||||
}
|
||||
extractBtn.title = t("extractToCurrent") + ": " + itemTitle(zips);
|
||||
|
||||
extractBtn.hidden = false;
|
||||
|
||||
// 只选中子卷(比如 .part02.rar),没有对应主卷 → 按钮置灰 + 提示改选主卷
|
||||
if (archives.length !== 1) {
|
||||
extractBtn.title = t("extractSelectMainVolume");
|
||||
extractBtn.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
extractBtn.title = t("extractToCurrent") + ": " + itemTitle(archives);
|
||||
extractBtn.disabled = locked;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user