aboutsummaryrefslogtreecommitdiff
path: root/modules/core
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-03 06:00:40 +0200
committerAgando <roduccomm@gmail.com>2026-06-03 06:00:40 +0200
commit7a3c8e74ecbf28d7921433430023f4ccaf8426dc (patch)
treec16ae627d307990cd049a6113ab2685826c29733 /modules/core
parentaafb0fbde5289a45f9f818a00141f80b149be283 (diff)
auto: 2026-06-03_06:00 changes
Diffstat (limited to 'modules/core')
-rw-r--r--modules/core/module-fs.js88
1 files changed, 51 insertions, 37 deletions
diff --git a/modules/core/module-fs.js b/modules/core/module-fs.js
index b119343..160dccc 100644
--- a/modules/core/module-fs.js
+++ b/modules/core/module-fs.js
@@ -277,46 +277,60 @@ class FileSystemModule {
}
};
this.commands['upload'] = () => { document.getElementById('file-upload-input').click(); };
- this.commands['download'] = (args) => {
+ this.commands['download'] = async (args) => {
if(!args[0]) return this.terminal.print('Usage: download <filename>', 'warning');
const fname = args[0];
const content = this.terminal.fs.readFile(fname);
- if(content !== null && content !== undefined) {
- const size = content.length;
- const sizeStr = size > 1024 ? (size / 1024).toFixed(1) + ' KB' : size + ' B';
- // Desktop: programmatic click (works on desktop Chrome/Firefox)
- const blob = new Blob([content], {type: 'application/octet-stream'});
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url; a.download = fname;
- a.style.display = 'none';
- document.body.appendChild(a);
- a.click();
- setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 2000);
- // Mobile fallback: build a DOM button with real user gesture
- const line = document.createElement('div');
- line.className = 'output-line';
- const msg = document.createElement('span');
- msg.textContent = '⬇ ' + fname + ' (' + sizeStr + ') ';
- const btn = document.createElement('button');
- btn.textContent = '⬇ Download';
- btn.className = 'btn';
- btn.style.cssText = 'background:var(--bg-tertiary);border:1px solid var(--border-color);color:var(--success-color);padding:4px 12px;border-radius:4px;cursor:pointer;font-size:0.85em;min-height:36px;';
- btn.onclick = () => {
- const b = new Blob([this.terminal.fs.readFile(fname)], {type: 'application/octet-stream'});
- const u = URL.createObjectURL(b);
- const el = document.createElement('a');
- el.href = u; el.download = fname;
- el.style.display = 'none';
- document.body.appendChild(el);
- el.click();
- setTimeout(() => { document.body.removeChild(el); URL.revokeObjectURL(u); }, 2000);
- };
- line.appendChild(msg);
- line.appendChild(btn);
- this.terminal.outputContainer.appendChild(line);
- this.terminal.scrollToBottom();
- } else { this.terminal.print('download: ' + fname + ': No such file', 'error'); }
+ if(content === null || content === undefined) {
+ return this.terminal.print('download: ' + fname + ': No such file', 'error');
+ }
+ // Push to WebDAV first — this is the only path to a real file download on Telegram WebView
+ // because browser-based file downloads are blocked in WebViews
+ let downloadUrl = null;
+ if (this.terminal.moduleManager && this.terminal.moduleManager.modules.WebDAVModule) {
+ const wdav = this.terminal.moduleManager.modules.WebDAVModule;
+ if (wdav.config && wdav.config.url) {
+ try {
+ // Make sure /downloads/ dir exists
+ try { await wdav._ensureDir('/downloads'); } catch(e) {}
+ const resp = await wdav._webdavRequest('PUT', '/downloads/' + fname, {
+ body: content,
+ headers: { 'Content-Type': 'application/octet-stream' }
+ });
+ if (resp.ok || resp.status === 201 || resp.status === 204) {
+ // Build the public URL the user can tap
+ const baseUrl = wdav.config.url.replace(/\/+$/, '');
+ const hostMatch = baseUrl.match(/^(https?:\/\/[^\/]+)/);
+ const host = hostMatch ? hostMatch[1] : 'https://webx11.duckdns.org';
+ downloadUrl = host + '/spaces/' + wdav._spaceName + '/downloads/' + encodeURIComponent(fname);
+ this.terminal.print('Uploaded to: ' + downloadUrl, 'success');
+ } else {
+ this.terminal.print('WebDAV push failed: HTTP ' + resp.status, 'warning');
+ }
+ } catch (e) {
+ this.terminal.print('WebDAV push error: ' + e.message, 'warning');
+ }
+ } else {
+ this.terminal.print('WebDAV not configured. Run: webdav-config', 'warning');
+ }
+ }
+ // Build a visible anchor link — tap = real user gesture = native browser download bar
+ const size = content.length;
+ const sizeStr = size > 1024 ? (size / 1024).toFixed(1) + ' KB' : size + ' B';
+ const line = document.createElement('div');
+ line.className = 'output-line';
+ line.style.cssText = 'padding:8px 0;display:flex;align-items:center;gap:10px;flex-wrap:wrap;';
+ if (downloadUrl) {
+ line.innerHTML = '<span>⬇ ' + fname + ' (' + sizeStr + ') </span>' +
+ '<a href="' + downloadUrl + '" target="_blank" rel="noopener" ' +
+ 'style="background:var(--success-color);color:#000;border:none;padding:8px 16px;' +
+ 'border-radius:6px;cursor:pointer;font-size:0.9em;min-height:44px;' +
+ 'display:inline-flex;align-items:center;text-decoration:none;font-weight:bold;">⬇ Tap to download</a>';
+ } else {
+ line.innerHTML = '<span>⬇ ' + fname + ' (' + sizeStr + ') — run <code>webdav-config</code> first to enable downloads</span>';
+ }
+ this.terminal.outputContainer.appendChild(line);
+ this.terminal.scrollToBottom();
};
this.commands['vfs-export'] = () => {
const data = this.terminal.fs.root;