Skip to content

Commit f14996c

Browse files
lhzxbsdrclaude
andcommitted
feat: add Qiita, note.com adapters & Bluesky search-posts
Add three new platform adapters for Japanese and decentralized social platforms: - Qiita: search, user, articles (public API v2) - note.com: search (browser), user, articles (public API) - Bluesky: search-posts (public AT Protocol API) Addresses review feedback from jackwener#529: - URL-encode note search query to handle special characters - Update both README.md and README.zh-CN.md with new adapters - Add search-posts to Bluesky rows in both READMEs Closes jackwener#561 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ab58aa4 commit f14996c

14 files changed

Lines changed: 335 additions & 2 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ git clone git@github.com:jackwener/opencli.git && cd opencli && npm install && n
140140
| **spotify** | `auth` `status` `play` `pause` `next` `prev` `volume` `search` `queue` `shuffle` `repeat` |
141141
| **xianyu** | `search` `item` `chat` |
142142
| **xiaoe** | `courses` `detail` `catalog` `play-url` `content` |
143+
| **bluesky** | `search` `search-posts` `profile` `user` `feeds` `followers` `following` `thread` `trending` `starter-packs` |
144+
| **qiita** | `search` `user` `articles` |
145+
| **note.com** | `search` `user` `articles` |
143146

144147
79+ adapters in total — **[→ see all supported sites & commands](./docs/adapters/index.md)**
145148

README.zh-CN.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ npx skills add jackwener/opencli --skill opencli-oneshot # 快速命令参
200200
| **substack** | `feed` `search` `publication` | 浏览器 |
201201
| **pixiv** | `ranking` `search` `user` `illusts` `detail` `download` | 浏览器 |
202202
| **tiktok** | `explore` `search` `profile` `user` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `live` `notifications` `friends` | 浏览器 |
203-
| **bluesky** | `search` `trending` `user` `profile` `thread` `feeds` `followers` `following` `starter-packs` | 公开 |
203+
| **bluesky** | `search` `search-posts` `trending` `user` `profile` `thread` `feeds` `followers` `following` `starter-packs` | 公开 |
204+
| **qiita** | `search` `user` `articles` | 公开 |
205+
| **note.com** | `search` `user` `articles` | 公开 / 浏览器 |
204206
| **xianyu** | `search` `item` `chat` | 浏览器 |
205207
| **douyin** | `videos` `publish` `drafts` `draft` `delete` `stats` `profile` `update` `hashtag` `location` `activities` `collections` | 浏览器 |
206208
| **yuanbao** | `new` `ask` | 浏览器 |

clis/bluesky/search-posts.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
site: bluesky
2+
name: search-posts
3+
description: Search Bluesky posts
4+
domain: public.api.bsky.app
5+
strategy: public
6+
browser: false
7+
8+
args:
9+
query:
10+
type: str
11+
required: true
12+
positional: true
13+
description: Search query
14+
limit:
15+
type: int
16+
default: 25
17+
description: Number of results
18+
19+
pipeline:
20+
- fetch:
21+
url: https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts
22+
params:
23+
q: ${{ args.query }}
24+
limit: ${{ args.limit }}
25+
26+
- select: posts
27+
28+
- map:
29+
rank: ${{ index + 1 }}
30+
author: ${{ item.author.handle }}
31+
text: ${{ item.record.text }}
32+
likes: ${{ item.likeCount }}
33+
reposts: ${{ item.repostCount }}
34+
replies: ${{ item.replyCount }}
35+
36+
- limit: ${{ args.limit }}
37+
38+
columns: [rank, author, text, likes, reposts, replies]

clis/note/articles.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
site: note
2+
name: articles
3+
description: List articles by a note.com user
4+
domain: note.com
5+
strategy: public
6+
browser: false
7+
8+
args:
9+
username:
10+
type: str
11+
required: true
12+
positional: true
13+
description: "note.com username (urlname)"
14+
limit:
15+
type: int
16+
default: 6
17+
description: Number of articles
18+
19+
pipeline:
20+
- fetch:
21+
url: https://note.com/api/v2/creators/${{ args.username }}/contents
22+
params:
23+
kind: note
24+
page: "1"
25+
26+
- select: data.contents
27+
28+
- map:
29+
rank: ${{ index + 1 }}
30+
title: ${{ item.name }}
31+
likes: ${{ item.likeCount }}
32+
comments: ${{ item.commentCount }}
33+
created: "${{ item.publishAt ? item.publishAt.slice(0, 10) : '' }}"
34+
url: ${{ item.noteUrl }}
35+
36+
- limit: ${{ args.limit }}
37+
38+
columns: [rank, title, likes, comments, created, url]

clis/note/search.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
site: note
2+
name: search
3+
description: Search note.com articles
4+
domain: note.com
5+
strategy: cookie
6+
7+
args:
8+
query:
9+
type: str
10+
required: true
11+
positional: true
12+
description: Search query
13+
limit:
14+
type: int
15+
default: 10
16+
description: Number of results
17+
18+
pipeline:
19+
- navigate: https://note.com
20+
21+
- evaluate: |
22+
(async () => {
23+
const query = ${{ args.query | json }};
24+
const encoded = encodeURIComponent(query);
25+
window.location.href = `https://note.com/search?q=${encoded}&context=note&mode=search`;
26+
for (let i = 0; i < 20; i++) {
27+
await new Promise(r => setTimeout(r, 500));
28+
if (document.querySelectorAll('a[href*="/n/n"]').length > 0) break;
29+
}
30+
const links = document.querySelectorAll('a[href*="/n/n"]');
31+
const seen = new Set();
32+
const results = [];
33+
for (const a of links) {
34+
const href = a.getAttribute('href');
35+
if (!href || seen.has(href)) continue;
36+
seen.add(href);
37+
const title = a.textContent?.trim() || '';
38+
if (!title || title.length < 4) continue;
39+
const url = href.startsWith('http') ? href : 'https://note.com' + href;
40+
results.push({ title, url });
41+
}
42+
return results;
43+
})()
44+
45+
- map:
46+
rank: ${{ index + 1 }}
47+
title: ${{ item.title }}
48+
url: ${{ item.url }}
49+
50+
- limit: ${{ args.limit }}
51+
52+
columns: [rank, title, url]

clis/note/user.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
site: note
2+
name: user
3+
description: Get note.com user profile
4+
domain: note.com
5+
strategy: public
6+
browser: false
7+
8+
args:
9+
username:
10+
type: str
11+
required: true
12+
positional: true
13+
description: "note.com username (urlname)"
14+
15+
pipeline:
16+
- fetch:
17+
url: https://note.com/api/v2/creators/${{ args.username }}
18+
19+
- select: data
20+
21+
- map:
22+
id: ${{ item.urlname }}
23+
name: ${{ item.nickname }}
24+
bio: ${{ item.profile }}
25+
followers: ${{ item.followerCount }}
26+
following: ${{ item.followingCount }}
27+
articles: ${{ item.noteCount }}
28+
url: "https://note.com/${{ item.urlname }}"
29+
30+
columns: [id, name, bio, followers, following, articles, url]

clis/qiita/articles.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
site: qiita
2+
name: articles
3+
description: List articles by a Qiita user
4+
domain: qiita.com
5+
strategy: public
6+
browser: false
7+
8+
args:
9+
username:
10+
type: str
11+
required: true
12+
positional: true
13+
description: Qiita username
14+
limit:
15+
type: int
16+
default: 20
17+
description: Number of articles
18+
19+
pipeline:
20+
- fetch:
21+
url: https://qiita.com/api/v2/users/${{ args.username }}/items
22+
params:
23+
per_page: ${{ args.limit }}
24+
25+
- map:
26+
rank: ${{ index + 1 }}
27+
title: ${{ item.title }}
28+
likes: ${{ item.likes_count }}
29+
tags: ${{ item.tags.map(t => t.name).join(', ') }}
30+
created: ${{ item.created_at.slice(0, 10) }}
31+
url: ${{ item.url }}
32+
33+
- limit: ${{ args.limit }}
34+
35+
columns: [rank, title, likes, tags, created, url]

clis/qiita/search.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
site: qiita
2+
name: search
3+
description: Search Qiita articles
4+
domain: qiita.com
5+
strategy: public
6+
browser: false
7+
8+
args:
9+
query:
10+
type: str
11+
required: true
12+
positional: true
13+
description: Search query
14+
limit:
15+
type: int
16+
default: 20
17+
description: Number of results
18+
19+
pipeline:
20+
- fetch:
21+
url: https://qiita.com/api/v2/items
22+
params:
23+
query: ${{ args.query }}
24+
per_page: ${{ args.limit }}
25+
26+
- map:
27+
rank: ${{ index + 1 }}
28+
title: ${{ item.title }}
29+
author: ${{ item.user.id }}
30+
likes: ${{ item.likes_count }}
31+
tags: ${{ item.tags.map(t => t.name).join(', ') }}
32+
url: ${{ item.url }}
33+
34+
- limit: ${{ args.limit }}
35+
36+
columns: [rank, title, author, likes, tags, url]

clis/qiita/user.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
site: qiita
2+
name: user
3+
description: Get Qiita user profile
4+
domain: qiita.com
5+
strategy: public
6+
browser: false
7+
8+
args:
9+
username:
10+
type: str
11+
required: true
12+
positional: true
13+
description: Qiita username
14+
15+
pipeline:
16+
- fetch:
17+
url: https://qiita.com/api/v2/users/${{ args.username }}
18+
19+
- map:
20+
id: ${{ item.id }}
21+
name: ${{ item.name }}
22+
bio: ${{ item.description }}
23+
followers: ${{ item.followers_count }}
24+
following: ${{ item.followees_count }}
25+
items: ${{ item.items_count }}
26+
url: "https://qiita.com/${{ item.id }}"
27+
28+
columns: [id, name, bio, followers, following, items, url]

docs/.vitepress/config.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ export default defineConfig({
119119
{ text: 'LessWrong', link: '/adapters/browser/lesswrong' },
120120
{ text: 'Lobsters', link: '/adapters/browser/lobsters' },
121121
{ text: 'Steam', link: '/adapters/browser/steam' },
122+
{ text: 'Qiita', link: '/adapters/browser/qiita' },
123+
{ text: 'note.com', link: '/adapters/browser/note' },
122124
],
123125
},
124126
{

0 commit comments

Comments
 (0)