Skip to content

Commit 1d56dd7

Browse files
Astro-Hanjackwener
andauthored
fix(wikipedia): fix search arg name + add random and trending commands (#231)
* fix(wikipedia): fix search arg name + add random and trending commands - fix: search.ts referenced `args.keyword` but the argument is defined as `query`, causing the search term to always be undefined - feat: add `random` command (random article summary via REST API) - feat: add `trending` command (most-read articles, yesterday's data) All commands are PUBLIC strategy, no browser required, reuse wikiFetch. * refactor(wikipedia): extract shared types + add docs for random/trending - Extract WikiSummary, WikiMostReadArticle types to utils.ts - Extract EXTRACT_MAX_LEN/DESC_MAX_LEN constants - Add formatSummaryRow() helper to eliminate duplicate mapping in summary.ts and random.ts - Update docs with random and trending command examples --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
1 parent e98cf75 commit 1d56dd7

File tree

6 files changed

+116
-15
lines changed

6 files changed

+116
-15
lines changed

docs/adapters/browser/wikipedia.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
|---------|-------------|
99
| `opencli wikipedia search` | Search Wikipedia articles |
1010
| `opencli wikipedia summary` | Get Wikipedia article summary |
11+
| `opencli wikipedia random` | Get a random Wikipedia article |
12+
| `opencli wikipedia trending` | Most-read articles (yesterday) |
1113

1214
## Usage Examples
1315

@@ -16,10 +18,17 @@
1618
opencli wikipedia search "quantum computing" --limit 10
1719

1820
# Get article summary
19-
opencli wikipedia summary --title "Artificial intelligence"
21+
opencli wikipedia summary "Artificial intelligence"
2022

21-
# Search in other languages
23+
# Get a random article
24+
opencli wikipedia random
25+
26+
# Most-read articles (yesterday)
27+
opencli wikipedia trending --limit 5
28+
29+
# Use with other languages
2230
opencli wikipedia search "人工智能" --lang zh
31+
opencli wikipedia random --lang ja
2332

2433
# JSON output
2534
opencli wikipedia search "Rust" -f json

src/clis/wikipedia/random.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { CliError } from '../../errors.js';
2+
import { cli, Strategy } from '../../registry.js';
3+
import { type WikiSummary, formatSummaryRow, wikiFetch } from './utils.js';
4+
5+
cli({
6+
site: 'wikipedia',
7+
name: 'random',
8+
description: 'Get a random Wikipedia article',
9+
strategy: Strategy.PUBLIC,
10+
browser: false,
11+
args: [{ name: 'lang', default: 'en', help: 'Language code (e.g. en, zh, ja)' }],
12+
columns: ['title', 'description', 'extract', 'url'],
13+
func: async (_page, args) => {
14+
const lang = args.lang || 'en';
15+
const data = (await wikiFetch(lang, '/api/rest_v1/page/random/summary')) as WikiSummary;
16+
if (!data?.title) throw new CliError('NOT_FOUND', 'No random article returned', 'Try again');
17+
return [formatSummaryRow(data, lang)];
18+
},
19+
});

src/clis/wikipedia/search.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { cli, Strategy } from '../../registry.js';
21
import { CliError } from '../../errors.js';
2+
import { cli, Strategy } from '../../registry.js';
33
import { wikiFetch } from './utils.js';
44

5-
interface WikiSearchResult { title: string; snippet: string; }
5+
interface WikiSearchResult {
6+
title: string;
7+
snippet: string;
8+
}
69

710
cli({
811
site: 'wikipedia',
@@ -19,8 +22,11 @@ cli({
1922
func: async (_page, args) => {
2023
const limit = Math.max(1, Math.min(Number(args.limit), 50));
2124
const lang = args.lang || 'en';
22-
const q = encodeURIComponent(args.keyword);
23-
const data = await wikiFetch(lang, `/w/api.php?action=query&list=search&srsearch=${q}&srlimit=${limit}&format=json&utf8=1`) as { query?: { search?: WikiSearchResult[] } };
25+
const q = encodeURIComponent(args.query);
26+
const data = (await wikiFetch(
27+
lang,
28+
`/w/api.php?action=query&list=search&srsearch=${q}&srlimit=${limit}&format=json&utf8=1`,
29+
)) as { query?: { search?: WikiSearchResult[] } };
2430
const results = data?.query?.search;
2531
if (!results?.length) throw new CliError('NOT_FOUND', 'No articles found', 'Try a different keyword');
2632
return results.map((r) => ({

src/clis/wikipedia/summary.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { cli, Strategy } from '../../registry.js';
21
import { CliError } from '../../errors.js';
3-
import { wikiFetch } from './utils.js';
2+
import { cli, Strategy } from '../../registry.js';
3+
import { type WikiSummary, formatSummaryRow, wikiFetch } from './utils.js';
44

55
cli({
66
site: 'wikipedia',
@@ -16,13 +16,8 @@ cli({
1616
func: async (_page, args) => {
1717
const lang = args.lang || 'en';
1818
const title = encodeURIComponent(args.title.replace(/ /g, '_'));
19-
const data = await wikiFetch(lang, `/api/rest_v1/page/summary/${title}`) as { title?: string; description?: string; extract?: string; content_urls?: { desktop?: { page?: string } } };
19+
const data = (await wikiFetch(lang, `/api/rest_v1/page/summary/${title}`)) as WikiSummary;
2020
if (!data?.title) throw new CliError('NOT_FOUND', `Article "${args.title}" not found`, 'Try searching first: opencli wikipedia search <keyword>');
21-
return [{
22-
title: data.title,
23-
description: data.description ?? '-',
24-
extract: (data.extract ?? '').slice(0, 300),
25-
url: data.content_urls?.desktop?.page ?? `https://${lang}.wikipedia.org/wiki/${title}`,
26-
}];
21+
return [formatSummaryRow(data, lang)];
2722
},
2823
});

src/clis/wikipedia/trending.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { CliError } from '../../errors.js';
2+
import { cli, Strategy } from '../../registry.js';
3+
import { DESC_MAX_LEN, type WikiMostReadArticle, wikiFetch } from './utils.js';
4+
5+
cli({
6+
site: 'wikipedia',
7+
name: 'trending',
8+
description: 'Most-read Wikipedia articles (yesterday)',
9+
strategy: Strategy.PUBLIC,
10+
browser: false,
11+
args: [
12+
{ name: 'limit', type: 'int', default: 10, help: 'Max results' },
13+
{ name: 'lang', default: 'en', help: 'Language code (e.g. en, zh, ja)' },
14+
],
15+
columns: ['rank', 'title', 'description', 'views'],
16+
func: async (_page, args) => {
17+
const lang = args.lang || 'en';
18+
const limit = Math.max(1, Math.min(Number(args.limit), 50));
19+
20+
// Use yesterday's UTC date — Wikipedia API expects UTC and yesterday
21+
// guarantees data availability (today's aggregation may be incomplete).
22+
const d = new Date(Date.now() - 86_400_000);
23+
const yyyy = d.getUTCFullYear();
24+
const mm = String(d.getUTCMonth() + 1).padStart(2, '0');
25+
const dd = String(d.getUTCDate()).padStart(2, '0');
26+
27+
const data = (await wikiFetch(lang, `/api/rest_v1/feed/featured/${yyyy}/${mm}/${dd}`)) as {
28+
mostread?: { articles?: WikiMostReadArticle[] };
29+
};
30+
const articles = data?.mostread?.articles;
31+
if (!articles?.length)
32+
throw new CliError('NOT_FOUND', 'No trending articles available', 'Try a different language with --lang');
33+
34+
return articles.slice(0, limit).map((a, i) => ({
35+
rank: i + 1,
36+
title: a.title ?? '-',
37+
description: (a.description ?? '-').slice(0, DESC_MAX_LEN),
38+
views: a.views ?? 0,
39+
}));
40+
},
41+
});

src/clis/wikipedia/utils.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,27 @@
88

99
import { CliError } from '../../errors.js';
1010

11+
/** Maximum character length for article extract fields. */
12+
export const EXTRACT_MAX_LEN = 300;
13+
14+
/** Maximum character length for short description fields. */
15+
export const DESC_MAX_LEN = 80;
16+
17+
/** Response shape shared by /page/summary and /page/random/summary endpoints. */
18+
export interface WikiSummary {
19+
title?: string;
20+
description?: string;
21+
extract?: string;
22+
content_urls?: { desktop?: { page?: string } };
23+
}
24+
25+
/** Article entry returned by the /feed/featured most-read endpoint. */
26+
export interface WikiMostReadArticle {
27+
title?: string;
28+
description?: string;
29+
views?: number;
30+
}
31+
1132
export async function wikiFetch(lang: string, path: string): Promise<unknown> {
1233
const url = `https://${lang}.wikipedia.org${path}`;
1334
const resp = await fetch(url, {
@@ -18,3 +39,13 @@ export async function wikiFetch(lang: string, path: string): Promise<unknown> {
1839
}
1940
return resp.json();
2041
}
42+
43+
/** Map a WikiSummary API response to the standard output row. */
44+
export function formatSummaryRow(data: WikiSummary, lang: string) {
45+
return {
46+
title: data.title!,
47+
description: data.description ?? '-',
48+
extract: (data.extract ?? '').slice(0, EXTRACT_MAX_LEN),
49+
url: data.content_urls?.desktop?.page ?? `https://${lang}.wikipedia.org`,
50+
};
51+
}

0 commit comments

Comments
 (0)