mirror of
https://github.com/LisherSong/ps5-web-file-manager.git
synced 2026-10-06 08:00:23 +02:00
- 前端:解压前弹出目标目录对话框,支持手改路径与「浏览目录」导航 选择器逐级选目录;冲突策略、7z 密码、大文件模式一并纳入。后端 /api/extract 原本就收 dst_dir,无需改动。上传即解压仍落当前路径。 - pkg_installer.c:元数据 ABI 由 0x38 改为原生 0x30(移除 Mono 托管层 多算的 slot/is_playgo_enabled 两个字段,旧布局会让 InstallByPackage 参数错位);安装前补 kernel_set_ucred_authid(0x4800000000000006), 权限失败以 PKG_INSTALL_PRIV_FAILED 区分;Makefile 链接 -lkernel_sys。 - i18n / HTML / CSS 同步新增解压对话框与目录选择器文案与样式。 注:PS5 专有改动(ABI/authid/链接)未经真机验证,需在 kstuff/etaHEN 环境实测安装路径是否真跑通。
256 lines
12 KiB
HTML
256 lines
12 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>PS5 Web File Manager</title>
|
|
<link rel="icon" type="image/png" href="/icon0.png">
|
|
<style>
|
|
html, body { margin: 0; min-height: 100%; background: #111316; color: #edf0f2; }
|
|
.init-loading {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
z-index: 20000;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #111316;
|
|
color: #aab4be;
|
|
font: 18px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
}
|
|
</style>
|
|
<link rel="stylesheet" href="/main.css">
|
|
</head>
|
|
<body>
|
|
<main class="shell">
|
|
<header class="topbar">
|
|
<div class="top-left">
|
|
<div id="path" class="path">/</div>
|
|
</div>
|
|
<div class="top-right">
|
|
<div id="spaceInfo" class="space-info"></div>
|
|
</div>
|
|
<button id="exitBtn" class="icon-button power-button" type="button" aria-label="Exit"></button>
|
|
</header>
|
|
|
|
<section class="toolbar">
|
|
<div class="tool-left">
|
|
<button id="copyBtn" data-i18n="copy"></button>
|
|
<button id="moveBtn" data-i18n="move"></button>
|
|
<button id="renameBtn" data-i18n="rename"></button>
|
|
<button id="downloadBtn" class="remote-only" data-i18n="download"></button>
|
|
<button id="deleteBtn" class="danger" data-i18n="delete"></button>
|
|
<button id="installPkgBtn" class="install-action" data-i18n="install" hidden></button>
|
|
<button id="extractBtn" class="extract-action" data-i18n="extract"></button>
|
|
<button id="pasteBtn" class="paste-action" hidden>
|
|
<span id="pasteVerb" data-i18n="paste"></span>
|
|
<span id="pasteName" class="paste-name"></span><span id="pasteCount" class="paste-count"></span>
|
|
<span id="pasteTargetText" data-i18n="pasteToCurrent"></span>
|
|
</button>
|
|
<button id="clearClipboardBtn" data-i18n="cancel" hidden></button>
|
|
</div>
|
|
<div class="tool-right">
|
|
<button id="refreshBtn" data-i18n="refresh"></button>
|
|
<div id="uploadGroup" class="upload-menu remote-only">
|
|
<button id="uploadBtn" class="upload-main" data-i18n="upload"
|
|
aria-haspopup="menu" aria-expanded="false"></button>
|
|
<div id="uploadMenu" class="upload-menu-list" role="menu" hidden>
|
|
<button id="uploadFilesItem" type="button" role="menuitem" data-i18n="uploadFiles"></button>
|
|
<button id="uploadFolderItem" type="button" role="menuitem" data-i18n="uploadFolder"></button>
|
|
</div>
|
|
</div>
|
|
<button id="newTextBtn" data-i18n="newText"></button>
|
|
<button id="mkdirBtn" data-i18n="mkdir"></button>
|
|
</div>
|
|
</section>
|
|
<input id="uploadFiles" type="file" multiple hidden>
|
|
<input id="uploadFolder" type="file" multiple webkitdirectory hidden>
|
|
|
|
<section id="content" class="content">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th class="select-col"><label class="select-hit"><input id="selectAll" type="checkbox"></label></th>
|
|
<th class="name-col sortable" data-sort="name">
|
|
<div class="name-head">
|
|
<button id="parentBtn" class="parent-nav-button" type="button" aria-label="Parent directory" disabled>
|
|
<img src="/icon-back.png" alt="">
|
|
</button>
|
|
<span class="name-heading" data-i18n="name"></span>
|
|
</div>
|
|
</th>
|
|
<th class="type-col sortable" data-sort="type" data-i18n="type"></th>
|
|
<th class="size-col sortable" data-sort="size" data-i18n="size"></th>
|
|
<th class="time-col sortable" data-sort="mtime" data-i18n="mtime"></th>
|
|
<th class="mode-col sortable" data-sort="mode" data-i18n="mode"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="files"></tbody>
|
|
</table>
|
|
<div id="empty" class="empty" data-i18n="empty" hidden></div>
|
|
<div id="contentLoading" class="content-loading" hidden>
|
|
<div class="content-loading-text" data-i18n="readDir"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<footer class="status">
|
|
<div id="statusText" data-i18n="ready"></div>
|
|
<div id="dropHint" class="status-hint remote-only" data-i18n="dropUploadHint" hidden></div>
|
|
<div id="versionText" class="version-text"></div>
|
|
</footer>
|
|
</main>
|
|
|
|
<div id="textEditorOverlay" class="text-editor-overlay" hidden>
|
|
<section class="text-editor-panel">
|
|
<div id="textEditorPath" class="text-editor-path"></div>
|
|
<textarea id="textEditor" class="text-editor" wrap="off" spellcheck="false"
|
|
autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>
|
|
<div id="textEditorStatus" class="text-editor-status"></div>
|
|
<div class="text-editor-actions">
|
|
<button id="textEditorCloseBtn" class="secondary" data-i18n="close"></button>
|
|
<button id="textEditorSaveBtn" class="primary" data-i18n="save"></button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div id="imagePreviewOverlay" class="text-editor-overlay" hidden>
|
|
<section class="text-editor-panel image-preview-panel">
|
|
<div id="imagePreviewName" class="text-editor-path"></div>
|
|
<div class="image-preview-stage">
|
|
<img id="imagePreview" class="image-preview" alt="">
|
|
</div>
|
|
<button id="imagePreviewCloseBtn" class="secondary" data-i18n="close"></button>
|
|
</section>
|
|
</div>
|
|
|
|
<div id="pkgInfoOverlay" class="text-editor-overlay" hidden>
|
|
<section class="text-editor-panel pkg-info-panel" role="dialog" aria-modal="true" aria-labelledby="pkgInfoTitle">
|
|
<h2 id="pkgInfoTitle" class="pkg-info-title" data-i18n="pkgInfoTitle"></h2>
|
|
<div class="pkg-info-content">
|
|
<div class="pkg-info-image-stage">
|
|
<img id="pkgInfoImage" class="pkg-info-image" src="/icon-pkg.png" alt="">
|
|
</div>
|
|
<div id="pkgInfoFields" class="pkg-info-fields"></div>
|
|
</div>
|
|
<div class="text-editor-actions">
|
|
<button id="pkgInfoCloseBtn" class="secondary" data-i18n="close"></button>
|
|
<button id="pkgInfoInstallBtn" class="primary" data-i18n="install"></button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div id="extractDialog" class="text-editor-overlay" hidden>
|
|
<section class="text-editor-panel extract-panel" role="dialog" aria-modal="true" aria-labelledby="extractTitle">
|
|
<h2 id="extractTitle" class="extract-title" data-i18n="extractDialogTitle"></h2>
|
|
<div class="extract-row">
|
|
<span class="extract-label" data-i18n="extractArchive"></span>
|
|
<span id="extractArchiveName" class="extract-archive-name"></span>
|
|
</div>
|
|
<label class="extract-field">
|
|
<span data-i18n="extractDestination"></span>
|
|
<span class="extract-dest-row">
|
|
<input id="extractDestInput" class="extract-dest-input" type="text"
|
|
spellcheck="false" autocomplete="off" autocapitalize="off">
|
|
<button id="extractBrowseBtn" type="button" class="secondary" data-i18n="browseFolder"></button>
|
|
</span>
|
|
</label>
|
|
<label class="extract-field">
|
|
<span data-i18n="extractConflict"></span>
|
|
<select id="extractConflictSelect" class="extract-select">
|
|
<option value="fail" data-i18n="extractConflictFail"></option>
|
|
<option value="overwrite" data-i18n="extractConflictOverwrite"></option>
|
|
<option value="merge" data-i18n="extractConflictMerge"></option>
|
|
</select>
|
|
</label>
|
|
<label id="extractPasswordField" class="extract-field" hidden>
|
|
<span data-i18n="extractPasswordLabel"></span>
|
|
<input id="extractPasswordInput" class="extract-password-input" type="text"
|
|
spellcheck="false" autocomplete="off" autocapitalize="off">
|
|
</label>
|
|
<label class="extract-field extract-large-field">
|
|
<input id="extractLargeCheck" type="checkbox">
|
|
<span data-i18n="extractLargeMode"></span>
|
|
</label>
|
|
<div class="text-editor-actions">
|
|
<button id="extractCancelBtn" type="button" class="secondary" data-i18n="cancel"></button>
|
|
<button id="extractConfirmBtn" type="button" class="primary" data-i18n="extract"></button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div id="folderPickerOverlay" class="text-editor-overlay" hidden>
|
|
<section class="text-editor-panel folder-picker-panel" role="dialog" aria-modal="true" aria-labelledby="folderPickerTitle">
|
|
<h2 id="folderPickerTitle" class="folder-picker-title" data-i18n="selectFolder"></h2>
|
|
<div id="folderPickerPath" class="folder-picker-path"></div>
|
|
<div id="folderPickerList" class="folder-picker-list"></div>
|
|
<div class="text-editor-actions">
|
|
<button id="folderPickerCancelBtn" type="button" class="secondary" data-i18n="cancel"></button>
|
|
<button id="folderPickerUpBtn" type="button" class="secondary" data-i18n="parent"></button>
|
|
<button id="folderPickerOkBtn" type="button" class="primary" data-i18n="selectHere"></button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div id="permissionOverlay" class="permission-overlay" hidden>
|
|
<section class="permission-panel" role="dialog" aria-modal="true" aria-labelledby="permissionTitle">
|
|
<h2 id="permissionTitle" class="permission-title" data-i18n="permissionsTitle"></h2>
|
|
<div id="permissionPath" class="permission-path"></div>
|
|
<div class="permission-grid">
|
|
<div class="permission-row permission-head" aria-hidden="true">
|
|
<span class="permission-scope"></span>
|
|
<span>R</span><span>W</span><span>X</span>
|
|
</div>
|
|
<div class="permission-row">
|
|
<span class="permission-scope" data-i18n="permissionOwner"></span>
|
|
<label><input id="permissionOwnerRead" type="checkbox"><span>R</span></label>
|
|
<label><input id="permissionOwnerWrite" type="checkbox"><span>W</span></label>
|
|
<label><input id="permissionOwnerExecute" type="checkbox"><span>X</span></label>
|
|
</div>
|
|
<div class="permission-row">
|
|
<span class="permission-scope" data-i18n="permissionGroup"></span>
|
|
<label><input id="permissionGroupRead" type="checkbox"><span>R</span></label>
|
|
<label><input id="permissionGroupWrite" type="checkbox"><span>W</span></label>
|
|
<label><input id="permissionGroupExecute" type="checkbox"><span>X</span></label>
|
|
</div>
|
|
<div class="permission-row">
|
|
<span class="permission-scope" data-i18n="permissionOther"></span>
|
|
<label><input id="permissionOtherRead" type="checkbox"><span>R</span></label>
|
|
<label><input id="permissionOtherWrite" type="checkbox"><span>W</span></label>
|
|
<label><input id="permissionOtherExecute" type="checkbox"><span>X</span></label>
|
|
</div>
|
|
</div>
|
|
<label class="permission-octal">
|
|
<span data-i18n="permissionOctal"></span>
|
|
<input id="permissionMode" type="text" inputmode="numeric" pattern="0[0-7]{3}"
|
|
minlength="4" maxlength="4" autocomplete="off" spellcheck="false">
|
|
</label>
|
|
<label id="permissionRecursiveOption" class="permission-recursive" hidden>
|
|
<input id="permissionRecursive" type="checkbox" checked>
|
|
<span data-i18n="permissionRecursive"></span>
|
|
</label>
|
|
<div class="permission-actions">
|
|
<button id="permissionCancelBtn" class="secondary" data-i18n="close"></button>
|
|
<button id="permissionApplyBtn" class="primary" data-i18n="apply"></button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div id="dropUploadOverlay" class="drop-upload-overlay remote-only" hidden>
|
|
<div class="drop-upload-message" data-i18n="dropUpload"></div>
|
|
</div>
|
|
|
|
<div id="taskOverlay" class="task-overlay" hidden>
|
|
<div class="task-panel">
|
|
<div id="tasks" class="tasks"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="initLoading" class="init-loading" aria-hidden="true">Loading...</div>
|
|
|
|
<script src="/main.js"></script>
|
|
</body>
|
|
</html>
|