pal-explorer-cli 0.4.12 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -149
- package/bin/pal.js +63 -2
- package/extensions/@palexplorer/analytics/extension.json +20 -1
- package/extensions/@palexplorer/analytics/index.js +19 -9
- package/extensions/@palexplorer/audit/extension.json +14 -0
- package/extensions/@palexplorer/auth-email/extension.json +15 -0
- package/extensions/@palexplorer/auth-oauth/extension.json +15 -0
- package/extensions/@palexplorer/chat/extension.json +14 -0
- package/extensions/@palexplorer/discovery/extension.json +17 -0
- package/extensions/@palexplorer/discovery/index.js +1 -1
- package/extensions/@palexplorer/email-notifications/extension.json +23 -0
- package/extensions/@palexplorer/groups/extension.json +15 -0
- package/extensions/@palexplorer/share-links/extension.json +15 -0
- package/extensions/@palexplorer/sync/extension.json +16 -0
- package/extensions/@palexplorer/user-mgmt/extension.json +15 -0
- package/lib/capabilities.js +24 -24
- package/lib/commands/analytics.js +175 -175
- package/lib/commands/api-keys.js +131 -131
- package/lib/commands/audit.js +235 -235
- package/lib/commands/auth.js +137 -137
- package/lib/commands/backup.js +76 -76
- package/lib/commands/billing.js +148 -148
- package/lib/commands/chat.js +217 -217
- package/lib/commands/cloud-backup.js +231 -231
- package/lib/commands/comment.js +99 -99
- package/lib/commands/completion.js +203 -203
- package/lib/commands/compliance.js +218 -218
- package/lib/commands/config.js +136 -136
- package/lib/commands/connect.js +44 -44
- package/lib/commands/dept.js +294 -294
- package/lib/commands/device.js +146 -146
- package/lib/commands/download.js +240 -226
- package/lib/commands/explorer.js +178 -178
- package/lib/commands/extension.js +1060 -970
- package/lib/commands/favorite.js +90 -90
- package/lib/commands/federation.js +270 -270
- package/lib/commands/file.js +533 -533
- package/lib/commands/group.js +271 -271
- package/lib/commands/gui-share.js +29 -29
- package/lib/commands/init.js +61 -61
- package/lib/commands/invite.js +59 -59
- package/lib/commands/list.js +58 -58
- package/lib/commands/log.js +116 -116
- package/lib/commands/nearby.js +108 -108
- package/lib/commands/network.js +251 -251
- package/lib/commands/notify.js +198 -198
- package/lib/commands/org.js +273 -273
- package/lib/commands/pal.js +403 -180
- package/lib/commands/permissions.js +216 -216
- package/lib/commands/pin.js +97 -97
- package/lib/commands/protocol.js +357 -357
- package/lib/commands/rbac.js +147 -147
- package/lib/commands/recover.js +36 -36
- package/lib/commands/register.js +171 -171
- package/lib/commands/relay.js +131 -131
- package/lib/commands/remote.js +368 -368
- package/lib/commands/revoke.js +50 -50
- package/lib/commands/scanner.js +280 -280
- package/lib/commands/schedule.js +344 -344
- package/lib/commands/scim.js +203 -203
- package/lib/commands/search.js +181 -181
- package/lib/commands/serve.js +438 -438
- package/lib/commands/server.js +350 -350
- package/lib/commands/share-link.js +199 -199
- package/lib/commands/share.js +336 -323
- package/lib/commands/sso.js +200 -200
- package/lib/commands/status.js +145 -145
- package/lib/commands/stream.js +562 -562
- package/lib/commands/su.js +187 -187
- package/lib/commands/sync.js +979 -979
- package/lib/commands/transfers.js +152 -152
- package/lib/commands/uninstall.js +188 -188
- package/lib/commands/update.js +204 -204
- package/lib/commands/user.js +276 -276
- package/lib/commands/vfs.js +84 -84
- package/lib/commands/web-login.js +79 -79
- package/lib/commands/web.js +52 -52
- package/lib/commands/webhook.js +180 -180
- package/lib/commands/whoami.js +59 -59
- package/lib/commands/workspace.js +121 -121
- package/lib/core/billing.js +16 -5
- package/lib/core/dhtDiscovery.js +9 -2
- package/lib/core/discoveryClient.js +13 -7
- package/lib/core/extensions.js +142 -1
- package/lib/core/identity.js +33 -2
- package/lib/core/imageProcessor.js +109 -0
- package/lib/core/imageTorrent.js +167 -0
- package/lib/core/permissions.js +1 -1
- package/lib/core/pro.js +11 -4
- package/lib/core/serverList.js +4 -1
- package/lib/core/shares.js +12 -1
- package/lib/core/signalingServer.js +14 -2
- package/lib/core/su.js +1 -1
- package/lib/core/users.js +1 -1
- package/lib/protocol/messages.js +12 -3
- package/lib/utils/explorer.js +1 -1
- package/lib/utils/help.js +357 -357
- package/lib/utils/torrent.js +1 -0
- package/package.json +4 -3
package/lib/commands/search.js
CHANGED
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { getIdentity } from '../core/identity.js';
|
|
3
|
-
import { getPrimaryServer } from '../core/discoveryClient.js';
|
|
4
|
-
import { formatSize } from '../utils/format.js';
|
|
5
|
-
|
|
6
|
-
function truncate(str, len) {
|
|
7
|
-
if (!str) return '';
|
|
8
|
-
return str.length > len ? str.slice(0, len - 1) + '\u2026' : str;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default function searchCommand(program) {
|
|
12
|
-
program
|
|
13
|
-
.command('search <query>')
|
|
14
|
-
.description('search for files, pals, or groups on the network')
|
|
15
|
-
.option('--kind <kind>', 'Search kind: files, pals, or groups', 'files')
|
|
16
|
-
.option('--scope <scope>', 'Search scope: public, group, or pal', 'public')
|
|
17
|
-
.option('--type <type>', 'File type: file or directory')
|
|
18
|
-
.option('--category <cat>', 'Category: documents, images, music, video, archives, code')
|
|
19
|
-
.option('--extension <ext>', 'Filter by file extension')
|
|
20
|
-
.option('--min-size <mb>', 'Minimum size in MB', parseFloat)
|
|
21
|
-
.option('--max-size <mb>', 'Maximum size in MB', parseFloat)
|
|
22
|
-
.option('--after <date>', 'Files shared after date (YYYY-MM-DD)')
|
|
23
|
-
.option('--before <date>', 'Files shared before date (YYYY-MM-DD)')
|
|
24
|
-
.option('--case-sensitive', 'Case-sensitive search')
|
|
25
|
-
.option('--sort <field>', 'Sort by: name, date, size, relevance', 'relevance')
|
|
26
|
-
.option('--limit <n>', 'Max results', parseInt, 20)
|
|
27
|
-
.addHelpText('after', `
|
|
28
|
-
Examples:
|
|
29
|
-
$
|
|
30
|
-
$
|
|
31
|
-
$
|
|
32
|
-
$
|
|
33
|
-
`)
|
|
34
|
-
.action(async (query, opts) => {
|
|
35
|
-
try {
|
|
36
|
-
const identity = await getIdentity();
|
|
37
|
-
const server = getPrimaryServer();
|
|
38
|
-
const jsonMode = program.opts().json;
|
|
39
|
-
|
|
40
|
-
if (opts.kind === 'pals') {
|
|
41
|
-
const res = await fetch(`${server}/api/v1/directory?q=${encodeURIComponent(query)}`, {
|
|
42
|
-
signal: AbortSignal.timeout(10000),
|
|
43
|
-
});
|
|
44
|
-
if (!res.ok) throw new Error(`Search failed: ${res.statusText}`);
|
|
45
|
-
const data = await res.json();
|
|
46
|
-
const results = data.results || [];
|
|
47
|
-
if (results.length === 0) {
|
|
48
|
-
if (jsonMode) { console.log(JSON.stringify({ kind: 'pals', query, results: [] }, null, 2)); return; }
|
|
49
|
-
console.log(chalk.gray(`No pals found for "${query}".`));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (jsonMode) {
|
|
53
|
-
console.log(JSON.stringify({ kind: 'pals', query, results }, null, 2));
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
console.log('');
|
|
57
|
-
console.log(chalk.cyan('Handle'.padEnd(20) + 'Public Key'));
|
|
58
|
-
console.log(chalk.gray('-'.repeat(60)));
|
|
59
|
-
for (const r of results) {
|
|
60
|
-
console.log(`${chalk.white(`@${r.handle}`).padEnd(20)}${chalk.gray(r.publicKey)}`);
|
|
61
|
-
}
|
|
62
|
-
console.log(chalk.gray(`\n${results.length} result(s)`));
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (opts.kind === 'groups') {
|
|
67
|
-
const res = await fetch(`${server}/api/v1/groups/search?q=${encodeURIComponent(query)}`, {
|
|
68
|
-
signal: AbortSignal.timeout(10000),
|
|
69
|
-
});
|
|
70
|
-
if (!res.ok) throw new Error(`Search failed: ${res.statusText}`);
|
|
71
|
-
const data = await res.json();
|
|
72
|
-
const results = data.results || [];
|
|
73
|
-
if (results.length === 0) {
|
|
74
|
-
if (jsonMode) { console.log(JSON.stringify({ kind: 'groups', query, results: [] }, null, 2)); return; }
|
|
75
|
-
console.log(chalk.gray(`No groups found for "${query}".`));
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (jsonMode) {
|
|
79
|
-
console.log(JSON.stringify({ kind: 'groups', query, results }, null, 2));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
console.log('');
|
|
83
|
-
console.log(chalk.cyan('Group Name'.padEnd(30) + 'Members'.padEnd(10) + 'Owner'));
|
|
84
|
-
console.log(chalk.gray('-'.repeat(65)));
|
|
85
|
-
for (const r of results) {
|
|
86
|
-
const name = truncate(r.name, 29).padEnd(30);
|
|
87
|
-
const members = String(r.memberCount || 0).padEnd(10);
|
|
88
|
-
const owner = r.ownerHandle ? `@${r.ownerHandle}` : r.owner.slice(0, 16) + '...';
|
|
89
|
-
console.log(`${chalk.white(name)}${chalk.yellow(members)}${chalk.cyan(owner)}`);
|
|
90
|
-
if (r.description) console.log(chalk.gray(` > ${truncate(r.description, 60)}`));
|
|
91
|
-
}
|
|
92
|
-
console.log(chalk.gray(`\n${results.length} result(s)`));
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Default: kind === 'files'
|
|
97
|
-
const params = new URLSearchParams({ q: query });
|
|
98
|
-
if (opts.scope) params.set('scope', opts.scope);
|
|
99
|
-
if (opts.type) params.set('type', opts.type);
|
|
100
|
-
if (opts.category) params.set('category', opts.category);
|
|
101
|
-
if (opts.extension) params.set('extension', opts.extension);
|
|
102
|
-
if (opts.minSize) params.set('minSize', opts.minSize);
|
|
103
|
-
if (opts.maxSize) params.set('maxSize', opts.maxSize);
|
|
104
|
-
if (opts.after) params.set('after', opts.after);
|
|
105
|
-
if (opts.before) params.set('before', opts.before);
|
|
106
|
-
if (opts.caseSensitive) params.set('caseSensitive', 'true');
|
|
107
|
-
if (opts.sort) params.set('sort', opts.sort);
|
|
108
|
-
if (opts.limit) params.set('limit', opts.limit);
|
|
109
|
-
|
|
110
|
-
const headers = {};
|
|
111
|
-
if (identity?.publicKey) headers['X-Public-Key'] = identity.publicKey;
|
|
112
|
-
if (identity?.handle) headers['X-Handle'] = identity.handle;
|
|
113
|
-
|
|
114
|
-
const res = await fetch(`${server}/api/v1/search?${params}`, {
|
|
115
|
-
headers,
|
|
116
|
-
signal: AbortSignal.timeout(15000),
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
if (!res.ok) {
|
|
120
|
-
const err = await res.json().catch(() => ({}));
|
|
121
|
-
console.log(chalk.red(`Search failed: ${err.error || res.statusText}`));
|
|
122
|
-
process.exitCode = 1;
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const data = await res.json();
|
|
127
|
-
const results = data.results || data;
|
|
128
|
-
|
|
129
|
-
if (!Array.isArray(results) || results.length === 0) {
|
|
130
|
-
if (jsonMode) { console.log(JSON.stringify({ kind: 'files', query, results: [], total: 0 }, null, 2)); return; }
|
|
131
|
-
console.log(chalk.gray(`No results for "${query}".`));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (jsonMode) {
|
|
136
|
-
console.log(JSON.stringify({ kind: 'files', query, results, total: data.total || results.length }, null, 2));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const nameW = 35;
|
|
141
|
-
const sizeW = 10;
|
|
142
|
-
const typeW = 10;
|
|
143
|
-
const ownerW = 15;
|
|
144
|
-
const dateW = 12;
|
|
145
|
-
const seedW = 7;
|
|
146
|
-
|
|
147
|
-
console.log('');
|
|
148
|
-
console.log(
|
|
149
|
-
chalk.cyan(
|
|
150
|
-
'Name'.padEnd(nameW) +
|
|
151
|
-
'Size'.padEnd(sizeW) +
|
|
152
|
-
'Type'.padEnd(typeW) +
|
|
153
|
-
'Owner'.padEnd(ownerW) +
|
|
154
|
-
'Date'.padEnd(dateW) +
|
|
155
|
-
'Seeders'
|
|
156
|
-
)
|
|
157
|
-
);
|
|
158
|
-
console.log(chalk.gray('-'.repeat(nameW + sizeW + typeW + ownerW + dateW + seedW)));
|
|
159
|
-
|
|
160
|
-
for (const r of results) {
|
|
161
|
-
const name = truncate(r.name || r.filename || '?', nameW - 1).padEnd(nameW);
|
|
162
|
-
const size = formatSize(r.size).padEnd(sizeW);
|
|
163
|
-
const type = (r.type || r.category || '-').padEnd(typeW);
|
|
164
|
-
const owner = truncate(r.owner || r.handle || '-', ownerW - 1).padEnd(ownerW);
|
|
165
|
-
const date = r.date || r.sharedAt ? new Date(r.date || r.sharedAt).toLocaleDateString() : '-';
|
|
166
|
-
const seeders = r.seeders != null ? String(r.seeders) : '-';
|
|
167
|
-
|
|
168
|
-
console.log(
|
|
169
|
-
`${chalk.white(name)}${chalk.yellow(size)}${chalk.gray(type)}${chalk.cyan(owner)}${chalk.gray(date.padEnd(dateW))}${chalk.green(seeders)}`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
console.log('');
|
|
174
|
-
const total = data.total || results.length;
|
|
175
|
-
console.log(chalk.gray(`${results.length} result(s)${total > results.length ? ` of ${total} total` : ''}`));
|
|
176
|
-
} catch (err) {
|
|
177
|
-
console.log(chalk.red(`Error: ${err.message}`));
|
|
178
|
-
process.exitCode = 1;
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { getIdentity } from '../core/identity.js';
|
|
3
|
+
import { getPrimaryServer } from '../core/discoveryClient.js';
|
|
4
|
+
import { formatSize } from '../utils/format.js';
|
|
5
|
+
|
|
6
|
+
function truncate(str, len) {
|
|
7
|
+
if (!str) return '';
|
|
8
|
+
return str.length > len ? str.slice(0, len - 1) + '\u2026' : str;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function searchCommand(program) {
|
|
12
|
+
program
|
|
13
|
+
.command('search <query>')
|
|
14
|
+
.description('search for files, pals, or groups on the network')
|
|
15
|
+
.option('--kind <kind>', 'Search kind: files, pals, or groups', 'files')
|
|
16
|
+
.option('--scope <scope>', 'Search scope: public, group, or pal', 'public')
|
|
17
|
+
.option('--type <type>', 'File type: file or directory')
|
|
18
|
+
.option('--category <cat>', 'Category: documents, images, music, video, archives, code')
|
|
19
|
+
.option('--extension <ext>', 'Filter by file extension')
|
|
20
|
+
.option('--min-size <mb>', 'Minimum size in MB', parseFloat)
|
|
21
|
+
.option('--max-size <mb>', 'Maximum size in MB', parseFloat)
|
|
22
|
+
.option('--after <date>', 'Files shared after date (YYYY-MM-DD)')
|
|
23
|
+
.option('--before <date>', 'Files shared before date (YYYY-MM-DD)')
|
|
24
|
+
.option('--case-sensitive', 'Case-sensitive search')
|
|
25
|
+
.option('--sort <field>', 'Sort by: name, date, size, relevance', 'relevance')
|
|
26
|
+
.option('--limit <n>', 'Max results', parseInt, 20)
|
|
27
|
+
.addHelpText('after', `
|
|
28
|
+
Examples:
|
|
29
|
+
$ pal search "project plans" Search public shares
|
|
30
|
+
$ pal search "alice" --kind pals Search for users
|
|
31
|
+
$ pal search "linux" --kind groups Search for groups
|
|
32
|
+
$ pal search "*.pdf" --category documents Search for PDFs
|
|
33
|
+
`)
|
|
34
|
+
.action(async (query, opts) => {
|
|
35
|
+
try {
|
|
36
|
+
const identity = await getIdentity();
|
|
37
|
+
const server = getPrimaryServer();
|
|
38
|
+
const jsonMode = program.opts().json;
|
|
39
|
+
|
|
40
|
+
if (opts.kind === 'pals') {
|
|
41
|
+
const res = await fetch(`${server}/api/v1/directory?q=${encodeURIComponent(query)}`, {
|
|
42
|
+
signal: AbortSignal.timeout(10000),
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) throw new Error(`Search failed: ${res.statusText}`);
|
|
45
|
+
const data = await res.json();
|
|
46
|
+
const results = data.results || [];
|
|
47
|
+
if (results.length === 0) {
|
|
48
|
+
if (jsonMode) { console.log(JSON.stringify({ kind: 'pals', query, results: [] }, null, 2)); return; }
|
|
49
|
+
console.log(chalk.gray(`No pals found for "${query}".`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (jsonMode) {
|
|
53
|
+
console.log(JSON.stringify({ kind: 'pals', query, results }, null, 2));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log(chalk.cyan('Handle'.padEnd(20) + 'Public Key'));
|
|
58
|
+
console.log(chalk.gray('-'.repeat(60)));
|
|
59
|
+
for (const r of results) {
|
|
60
|
+
console.log(`${chalk.white(`@${r.handle}`).padEnd(20)}${chalk.gray(r.publicKey)}`);
|
|
61
|
+
}
|
|
62
|
+
console.log(chalk.gray(`\n${results.length} result(s)`));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (opts.kind === 'groups') {
|
|
67
|
+
const res = await fetch(`${server}/api/v1/groups/search?q=${encodeURIComponent(query)}`, {
|
|
68
|
+
signal: AbortSignal.timeout(10000),
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok) throw new Error(`Search failed: ${res.statusText}`);
|
|
71
|
+
const data = await res.json();
|
|
72
|
+
const results = data.results || [];
|
|
73
|
+
if (results.length === 0) {
|
|
74
|
+
if (jsonMode) { console.log(JSON.stringify({ kind: 'groups', query, results: [] }, null, 2)); return; }
|
|
75
|
+
console.log(chalk.gray(`No groups found for "${query}".`));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (jsonMode) {
|
|
79
|
+
console.log(JSON.stringify({ kind: 'groups', query, results }, null, 2));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log('');
|
|
83
|
+
console.log(chalk.cyan('Group Name'.padEnd(30) + 'Members'.padEnd(10) + 'Owner'));
|
|
84
|
+
console.log(chalk.gray('-'.repeat(65)));
|
|
85
|
+
for (const r of results) {
|
|
86
|
+
const name = truncate(r.name, 29).padEnd(30);
|
|
87
|
+
const members = String(r.memberCount || 0).padEnd(10);
|
|
88
|
+
const owner = r.ownerHandle ? `@${r.ownerHandle}` : r.owner.slice(0, 16) + '...';
|
|
89
|
+
console.log(`${chalk.white(name)}${chalk.yellow(members)}${chalk.cyan(owner)}`);
|
|
90
|
+
if (r.description) console.log(chalk.gray(` > ${truncate(r.description, 60)}`));
|
|
91
|
+
}
|
|
92
|
+
console.log(chalk.gray(`\n${results.length} result(s)`));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Default: kind === 'files'
|
|
97
|
+
const params = new URLSearchParams({ q: query });
|
|
98
|
+
if (opts.scope) params.set('scope', opts.scope);
|
|
99
|
+
if (opts.type) params.set('type', opts.type);
|
|
100
|
+
if (opts.category) params.set('category', opts.category);
|
|
101
|
+
if (opts.extension) params.set('extension', opts.extension);
|
|
102
|
+
if (opts.minSize) params.set('minSize', opts.minSize);
|
|
103
|
+
if (opts.maxSize) params.set('maxSize', opts.maxSize);
|
|
104
|
+
if (opts.after) params.set('after', opts.after);
|
|
105
|
+
if (opts.before) params.set('before', opts.before);
|
|
106
|
+
if (opts.caseSensitive) params.set('caseSensitive', 'true');
|
|
107
|
+
if (opts.sort) params.set('sort', opts.sort);
|
|
108
|
+
if (opts.limit) params.set('limit', opts.limit);
|
|
109
|
+
|
|
110
|
+
const headers = {};
|
|
111
|
+
if (identity?.publicKey) headers['X-Public-Key'] = identity.publicKey;
|
|
112
|
+
if (identity?.handle) headers['X-Handle'] = identity.handle;
|
|
113
|
+
|
|
114
|
+
const res = await fetch(`${server}/api/v1/search?${params}`, {
|
|
115
|
+
headers,
|
|
116
|
+
signal: AbortSignal.timeout(15000),
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (!res.ok) {
|
|
120
|
+
const err = await res.json().catch(() => ({}));
|
|
121
|
+
console.log(chalk.red(`Search failed: ${err.error || res.statusText}`));
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const data = await res.json();
|
|
127
|
+
const results = data.results || data;
|
|
128
|
+
|
|
129
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
130
|
+
if (jsonMode) { console.log(JSON.stringify({ kind: 'files', query, results: [], total: 0 }, null, 2)); return; }
|
|
131
|
+
console.log(chalk.gray(`No results for "${query}".`));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (jsonMode) {
|
|
136
|
+
console.log(JSON.stringify({ kind: 'files', query, results, total: data.total || results.length }, null, 2));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const nameW = 35;
|
|
141
|
+
const sizeW = 10;
|
|
142
|
+
const typeW = 10;
|
|
143
|
+
const ownerW = 15;
|
|
144
|
+
const dateW = 12;
|
|
145
|
+
const seedW = 7;
|
|
146
|
+
|
|
147
|
+
console.log('');
|
|
148
|
+
console.log(
|
|
149
|
+
chalk.cyan(
|
|
150
|
+
'Name'.padEnd(nameW) +
|
|
151
|
+
'Size'.padEnd(sizeW) +
|
|
152
|
+
'Type'.padEnd(typeW) +
|
|
153
|
+
'Owner'.padEnd(ownerW) +
|
|
154
|
+
'Date'.padEnd(dateW) +
|
|
155
|
+
'Seeders'
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
console.log(chalk.gray('-'.repeat(nameW + sizeW + typeW + ownerW + dateW + seedW)));
|
|
159
|
+
|
|
160
|
+
for (const r of results) {
|
|
161
|
+
const name = truncate(r.name || r.filename || '?', nameW - 1).padEnd(nameW);
|
|
162
|
+
const size = formatSize(r.size).padEnd(sizeW);
|
|
163
|
+
const type = (r.type || r.category || '-').padEnd(typeW);
|
|
164
|
+
const owner = truncate(r.owner || r.handle || '-', ownerW - 1).padEnd(ownerW);
|
|
165
|
+
const date = r.date || r.sharedAt ? new Date(r.date || r.sharedAt).toLocaleDateString() : '-';
|
|
166
|
+
const seeders = r.seeders != null ? String(r.seeders) : '-';
|
|
167
|
+
|
|
168
|
+
console.log(
|
|
169
|
+
`${chalk.white(name)}${chalk.yellow(size)}${chalk.gray(type)}${chalk.cyan(owner)}${chalk.gray(date.padEnd(dateW))}${chalk.green(seeders)}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log('');
|
|
174
|
+
const total = data.total || results.length;
|
|
175
|
+
console.log(chalk.gray(`${results.length} result(s)${total > results.length ? ` of ${total} total` : ''}`));
|
|
176
|
+
} catch (err) {
|
|
177
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
178
|
+
process.exitCode = 1;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|