aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-fetcher.js
blob: fea84d253a1814877f2c849a7590cf8eb7ebba1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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');
        }
    }
}