diff --git a/dist/hpl-toolbox-0.1.3.exe b/dist/hpl-toolbox-0.1.4.exe similarity index 76% rename from dist/hpl-toolbox-0.1.3.exe rename to dist/hpl-toolbox-0.1.4.exe index 7381e12..171dd44 100644 Binary files a/dist/hpl-toolbox-0.1.3.exe and b/dist/hpl-toolbox-0.1.4.exe differ diff --git a/dist/hpl-toolbox-0.1.3.vsix b/dist/hpl-toolbox-0.1.4.vsix similarity index 73% rename from dist/hpl-toolbox-0.1.3.vsix rename to dist/hpl-toolbox-0.1.4.vsix index 26e270e..17623c7 100644 Binary files a/dist/hpl-toolbox-0.1.3.vsix and b/dist/hpl-toolbox-0.1.4.vsix differ diff --git a/package.json b/package.json index 76b8f02..3be4e99 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "hpl-toolbox", "displayName": "HPL Toolbox", "description": "Bundled tools: PLEC Upload, AppLovin Demo Upload, Base64 Asset Scanner, Daily Update. Local HTML Host.", - "version": "0.1.3", + "version": "0.1.4", "publisher": "hesukastro", "license": "UNLICENSED", "repository": { diff --git a/src/tools/applovinUpload.ts b/src/tools/applovinUpload.ts index f54b5f9..d8fbeb2 100644 --- a/src/tools/applovinUpload.ts +++ b/src/tools/applovinUpload.ts @@ -20,6 +20,7 @@ export function openApplovinUpload(_context: vscode.ExtensionContext) { canSelectMany: true, filters: { HTML: ['html', 'htm'] }, openLabel: 'Select', + defaultUri: getPickerDefaultUri(), }); if (picked && picked.length) { panel.webview.postMessage({ @@ -163,6 +164,17 @@ async function handleUpload(panel: vscode.WebviewPanel, filePaths: string[]) { panel.webview.postMessage({ type: 'done' }); } +function getPickerDefaultUri(): vscode.Uri | undefined { + const folders = vscode.workspace.workspaceFolders; + if (!folders || folders.length === 0) return undefined; + const root = folders[0].uri.fsPath; + const dist = path.join(root, 'dist'); + if (fs.existsSync(dist) && fs.statSync(dist).isDirectory()) { + return vscode.Uri.file(dist); + } + return vscode.Uri.file(root); +} + function qrBaseName(name: string): string { return (name || 'qr').replace(/\.html?$/i, '').replace(/[\\/:*?"<>|]/g, '_') || 'qr'; } diff --git a/src/tools/plecUpload.ts b/src/tools/plecUpload.ts index 2104147..f92b3b1 100644 --- a/src/tools/plecUpload.ts +++ b/src/tools/plecUpload.ts @@ -17,18 +17,16 @@ export function openPlecUpload(_context: vscode.ExtensionContext) { if (msg.type === 'pickFile') { const picked = await vscode.window.showOpenDialog({ - canSelectMany: false, + canSelectMany: true, filters: { HTML: ['html', 'htm'] }, openLabel: 'Select', defaultUri: getPickerDefaultUri(), }); - if (picked && picked[0]) { - const fp = picked[0].fsPath; + if (picked && picked.length) { panel.webview.postMessage({ - type: 'fileSelected', + type: 'filesSelected', rowId: msg.rowId, - path: fp, - name: path.basename(fp), + files: picked.map(u => ({ path: u.fsPath, name: path.basename(u.fsPath) })), }); } return; @@ -233,6 +231,12 @@ function getHtml(): string { const vscode = acquireVsCodeApi(); let nextId = 1; const tbody = document.querySelector('#rows tbody'); + + function parseIterationName(filename) { + const base = filename.replace(/\\.html?$/i, ''); + const match = base.match(/\\b(full|\\d+clk|\\d+s(?:ec)?)\\b/i); + return match ? match[1].toLowerCase() : base; + } const statusEl = document.getElementById('status'); const resultsEl = document.getElementById('results'); @@ -286,13 +290,22 @@ function getHtml(): string { window.addEventListener('message', (e) => { const m = e.data; - if (m.type === 'fileSelected') { - const tr = tbody.querySelector('tr[data-id="' + m.rowId + '"]'); - if (!tr) return; - tr.querySelector('[data-path]').value = m.path; - tr.querySelector('[data-name]').textContent = m.name; - const iter = tr.querySelector('[data-iter]'); - if (!iter.value) iter.value = m.name.replace(/\\.html?$/i, ''); + if (m.type === 'filesSelected') { + const firstTr = tbody.querySelector('tr[data-id="' + m.rowId + '"]'); + m.files.forEach(function(f, i) { + let tr; + if (i === 0) { + tr = firstTr; + } else { + addRow(); + tr = tbody.lastElementChild; + } + if (!tr) return; + tr.querySelector('[data-path]').value = f.path; + tr.querySelector('[data-name]').textContent = f.name; + const iter = tr.querySelector('[data-iter]'); + if (!iter.value) iter.value = parseIterationName(f.name); + }); } else if (m.type === 'status') { statusEl.textContent = m.message; statusEl.className = ''; diff --git a/standalone/applovin.go b/standalone/applovin.go index 1f50b21..e239778 100644 --- a/standalone/applovin.go +++ b/standalone/applovin.go @@ -236,11 +236,16 @@ function handle(m) { } func ApplovinPick(w http.ResponseWriter, r *http.Request) { + cfg := LoadConfig() picked := PickFiles( "Select HTML files", []FileFilter{{Name: "HTML", Extensions: []string{"html", "htm"}}}, - true, "", + true, cfg.LastPickDir, ) + if len(picked) > 0 { + cfg.LastPickDir = filepath.Dir(picked[0]) + _ = SaveConfig(cfg) + } files := make([]map[string]string, 0, len(picked)) for _, p := range picked { files = append(files, map[string]string{"path": p, "name": filepath.Base(p)}) diff --git a/standalone/platform.go b/standalone/platform.go index 5bc140d..da90e60 100644 --- a/standalone/platform.go +++ b/standalone/platform.go @@ -36,6 +36,7 @@ type AppConfig struct { Applovin ApplovinConfig `json:"applovin"` SendToMobile SendToMobileConfig `json:"sendToMobile"` DailyUpdate DailyUpdateConfig `json:"dailyUpdate"` + LastPickDir string `json:"lastPickDir,omitempty"` } var configMu sync.Mutex diff --git a/standalone/plec.go b/standalone/plec.go index 05f3917..26bf681 100644 --- a/standalone/plec.go +++ b/standalone/plec.go @@ -54,6 +54,12 @@ const tbody = document.querySelector('#rows tbody'); const statusEl = document.getElementById('status'); const resultsEl = document.getElementById('results'); +function parseIterationName(filename) { + const base = filename.replace(/\.html?$/i, ''); + const match = base.match(/\b(full|\d+clk|\d+s(?:ec)?)\b/i); + return match ? match[1].toLowerCase() : base; +} + function addRow() { const id = 'r' + (nextId++); const tr = document.createElement('tr'); @@ -73,11 +79,14 @@ function addRow() { tr.querySelector('.pick').addEventListener('click', async () => { const res = await fetch('/api/plec/pick', { method: 'POST' }); const j = await res.json(); - if (j.path) { - tr.querySelector('[data-path]').value = j.path; - tr.querySelector('[data-name]').textContent = j.name; - const iter = tr.querySelector('[data-iter]'); - if (!iter.value) iter.value = j.name.replace(/\.html?$/i, ''); + if (j.files && j.files.length) { + j.files.forEach(function(f, i) { + const target = i === 0 ? tr : (addRow(), tbody.lastElementChild); + target.querySelector('[data-path]').value = f.path; + target.querySelector('[data-name]').textContent = f.name; + const iter = target.querySelector('[data-iter]'); + if (!iter.value) iter.value = parseIterationName(f.name); + }); } }); tr.querySelector('.remove-btn').addEventListener('click', () => { @@ -163,16 +172,23 @@ addRow(); } func PlecPick(w http.ResponseWriter, r *http.Request) { + cfg := LoadConfig() picked := PickFiles( "Select HTML", []FileFilter{{Name: "HTML", Extensions: []string{"html", "htm"}}}, - false, "", + true, cfg.LastPickDir, ) if len(picked) == 0 { - writeJSON(w, map[string]any{"path": nil}) + writeJSON(w, map[string]any{"files": []any{}}) return } - writeJSON(w, map[string]any{"path": picked[0], "name": filepath.Base(picked[0])}) + cfg.LastPickDir = filepath.Dir(picked[0]) + _ = SaveConfig(cfg) + files := make([]map[string]string, 0, len(picked)) + for _, p := range picked { + files = append(files, map[string]string{"path": p, "name": filepath.Base(p)}) + } + writeJSON(w, map[string]any{"files": files}) } type plecRow struct {