diff options
| author | Agando <roduccomm@gmail.com> | 2026-05-25 18:02:02 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-05-25 18:02:02 +0200 |
| commit | 4baa484b84c5184286cac2743575251454a5ee2b (patch) | |
| tree | cb9002f93644f363d0f35831dc97e6492bbb0ed6 /modules/core/module-fetcher.js | |
auto: 2026-05-25_18:02 changes
Diffstat (limited to 'modules/core/module-fetcher.js')
| -rw-r--r-- | modules/core/module-fetcher.js | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/modules/core/module-fetcher.js b/modules/core/module-fetcher.js new file mode 100644 index 0000000..fea84d2 --- /dev/null +++ b/modules/core/module-fetcher.js @@ -0,0 +1,65 @@ +class WebFetcherModule { + constructor() { + this.commands = {}; + this.terminal = null; + } + getHelpInfo() { + return { + 'fetch': 'fetch <url> — Fetch and display raw HTML/text content from a URL', + 'web': 'web <url> — Alias for fetch', + 'extract': 'extract <url> — Extract readable article content (title + body text) from a URL', + }; + } + registerCommands() { + this.commands['fetch'] = (args) => this.fetchUrl(args); + this.commands['web'] = (args) => this.fetchUrl(args); + this.commands['extract'] = (args) => this.extractUrl(args); + } + async fetchUrl(args) { + if (!args[0]) { + this.terminal.print("Usage: fetch <url>", "warning"); + this.terminal.print("Example: fetch https://example.com", "info"); + return; + } + let url = args[0]; + if (!url.match(/^https?:\/\//i)) url = 'https://' + url; + this.terminal.print(`🌐 Fetching: ${url}`, "info"); + try { + const resp = await fetch('/api/fetch?url=' + encodeURIComponent(url)); + if (resp.status === 403) { this.terminal.print('Blocked: internal network addresses not allowed', 'error'); return; } + if (!resp.ok) { this.terminal.print('Fetch failed: HTTP ' + resp.status, 'error'); return; } + const text = await resp.text(); + const cleanText = text.replace(/\s+/g, ' ').trim(); + this.terminal.print(`\n=== Content from ${url} ===\n`, 'success'); + this.terminal.print(cleanText.substring(0, 3000) + (cleanText.length > 3000 ? '...' : '')); + this.terminal.print(`\n📏 Content Length: ${cleanText.length} chars`, 'info'); + } catch (e) { + this.terminal.print('Fetch failed: ' + e.message, 'error'); + } + } + async extractUrl(args) { + if (!args[0]) { + this.terminal.print("Usage: extract <url>", "warning"); + this.terminal.print("Example: extract https://example.com", "info"); + return; + } + let url = args[0]; + if (!url.match(/^https?:\/\//i)) url = 'https://' + url; + this.terminal.print(`📄 Extracting: ${url}`, "info"); + try { + const resp = await fetch('/api/extract?url=' + encodeURIComponent(url)); + if (resp.status === 403) { this.terminal.print('Blocked: internal network addresses not allowed', 'error'); return; } + if (!resp.ok) { + const err = await resp.json().catch(() => ({})); + this.terminal.print('Extract failed: ' + (err.error || 'HTTP ' + resp.status), 'error'); + return; + } + const data = await resp.json(); + if (data.title) this.terminal.print(`\n📰 ${data.title}\n`, 'success'); + this.terminal.print(data.content || '(no content extracted)'); + this.terminal.print(`\n📏 ${data.word_count || 0} words (via ${data.method || 'unknown'})`, 'info'); + } catch (e) { + this.terminal.print('Extract failed: ' + e.message, 'error'); + } + } +} |