From 28b65455ce6dff503d17b7a7158f0847fd593f5e Mon Sep 17 00:00:00 2001 From: lhzxbsdr Date: Sat, 28 Mar 2026 03:56:10 +0800 Subject: [PATCH 1/4] feat: add Qiita adapter (search, user, articles) Public REST API v2, no auth required. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/clis/qiita/articles.yaml | 35 +++++++++++++++++++++++++++++++++++ src/clis/qiita/search.yaml | 36 ++++++++++++++++++++++++++++++++++++ src/clis/qiita/user.yaml | 28 ++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/clis/qiita/articles.yaml create mode 100644 src/clis/qiita/search.yaml create mode 100644 src/clis/qiita/user.yaml diff --git a/src/clis/qiita/articles.yaml b/src/clis/qiita/articles.yaml new file mode 100644 index 00000000..d007e012 --- /dev/null +++ b/src/clis/qiita/articles.yaml @@ -0,0 +1,35 @@ +site: qiita +name: articles +description: List articles by a Qiita user +domain: qiita.com +strategy: public +browser: false + +args: + username: + type: str + required: true + positional: true + description: Qiita username + limit: + type: int + default: 20 + description: Number of articles + +pipeline: + - fetch: + url: https://qiita.com/api/v2/users/${{ args.username }}/items + params: + per_page: ${{ args.limit }} + + - map: + rank: ${{ index + 1 }} + title: ${{ item.title }} + likes: ${{ item.likes_count }} + tags: ${{ item.tags.map(t => t.name).join(', ') }} + created: ${{ item.created_at.slice(0, 10) }} + url: ${{ item.url }} + + - limit: ${{ args.limit }} + +columns: [rank, title, likes, tags, created, url] diff --git a/src/clis/qiita/search.yaml b/src/clis/qiita/search.yaml new file mode 100644 index 00000000..530a382b --- /dev/null +++ b/src/clis/qiita/search.yaml @@ -0,0 +1,36 @@ +site: qiita +name: search +description: Search Qiita articles +domain: qiita.com +strategy: public +browser: false + +args: + query: + type: str + required: true + positional: true + description: Search query + limit: + type: int + default: 20 + description: Number of results + +pipeline: + - fetch: + url: https://qiita.com/api/v2/items + params: + query: ${{ args.query }} + per_page: ${{ args.limit }} + + - map: + rank: ${{ index + 1 }} + title: ${{ item.title }} + author: ${{ item.user.id }} + likes: ${{ item.likes_count }} + tags: ${{ item.tags.map(t => t.name).join(', ') }} + url: ${{ item.url }} + + - limit: ${{ args.limit }} + +columns: [rank, title, author, likes, tags, url] diff --git a/src/clis/qiita/user.yaml b/src/clis/qiita/user.yaml new file mode 100644 index 00000000..332d6166 --- /dev/null +++ b/src/clis/qiita/user.yaml @@ -0,0 +1,28 @@ +site: qiita +name: user +description: Get Qiita user profile +domain: qiita.com +strategy: public +browser: false + +args: + username: + type: str + required: true + positional: true + description: Qiita username + +pipeline: + - fetch: + url: https://qiita.com/api/v2/users/${{ args.username }} + + - map: + id: ${{ item.id }} + name: ${{ item.name }} + bio: ${{ item.description }} + followers: ${{ item.followers_count }} + following: ${{ item.followees_count }} + items: ${{ item.items_count }} + url: "https://qiita.com/${{ item.id }}" + +columns: [id, name, bio, followers, following, items, url] From 75cf59ec44871c82b4d1519a4a808c98482c17c6 Mon Sep 17 00:00:00 2001 From: lhzxbsdr Date: Sat, 28 Mar 2026 03:56:14 +0800 Subject: [PATCH 2/4] feat: add Bluesky search-posts command Search posts via AT Protocol public API (app.bsky.feed.searchPosts). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/clis/bluesky/search-posts.yaml | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/clis/bluesky/search-posts.yaml diff --git a/src/clis/bluesky/search-posts.yaml b/src/clis/bluesky/search-posts.yaml new file mode 100644 index 00000000..b49d61a4 --- /dev/null +++ b/src/clis/bluesky/search-posts.yaml @@ -0,0 +1,38 @@ +site: bluesky +name: search-posts +description: Search Bluesky posts +domain: public.api.bsky.app +strategy: public +browser: false + +args: + query: + type: str + required: true + positional: true + description: Search query + limit: + type: int + default: 25 + description: Number of results + +pipeline: + - fetch: + url: https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts + params: + q: ${{ args.query }} + limit: ${{ args.limit }} + + - select: posts + + - map: + rank: ${{ index + 1 }} + author: ${{ item.author.handle }} + text: ${{ item.record.text }} + likes: ${{ item.likeCount }} + reposts: ${{ item.repostCount }} + replies: ${{ item.replyCount }} + + - limit: ${{ args.limit }} + +columns: [rank, author, text, likes, reposts, replies] From cc9120e7f764982f83cb48012c72ac365e13fd64 Mon Sep 17 00:00:00 2001 From: lhzxbsdr Date: Sat, 28 Mar 2026 03:56:19 +0800 Subject: [PATCH 3/4] feat: add note.com adapter (search, user, articles) User and articles use public API (no auth). Search uses cookie strategy (note.com requires login for search endpoint). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/clis/note/articles.yaml | 38 +++++++++++++++++++++++++++++++++++++ src/clis/note/search.yaml | 38 +++++++++++++++++++++++++++++++++++++ src/clis/note/user.yaml | 30 +++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 src/clis/note/articles.yaml create mode 100644 src/clis/note/search.yaml create mode 100644 src/clis/note/user.yaml diff --git a/src/clis/note/articles.yaml b/src/clis/note/articles.yaml new file mode 100644 index 00000000..b871ea9a --- /dev/null +++ b/src/clis/note/articles.yaml @@ -0,0 +1,38 @@ +site: note +name: articles +description: List articles by a note.com user +domain: note.com +strategy: public +browser: false + +args: + username: + type: str + required: true + positional: true + description: "note.com username (urlname)" + limit: + type: int + default: 6 + description: Number of articles + +pipeline: + - fetch: + url: https://note.com/api/v2/creators/${{ args.username }}/contents + params: + kind: note + page: "1" + + - select: data.contents + + - map: + rank: ${{ index + 1 }} + title: ${{ item.name }} + likes: ${{ item.likeCount }} + comments: ${{ item.commentCount }} + created: "${{ item.publishAt ? item.publishAt.slice(0, 10) : '' }}" + url: ${{ item.noteUrl }} + + - limit: ${{ args.limit }} + +columns: [rank, title, likes, comments, created, url] diff --git a/src/clis/note/search.yaml b/src/clis/note/search.yaml new file mode 100644 index 00000000..65453539 --- /dev/null +++ b/src/clis/note/search.yaml @@ -0,0 +1,38 @@ +site: note +name: search +description: Search note.com articles +domain: note.com +strategy: cookie + +args: + query: + type: str + required: true + positional: true + description: Search query + limit: + type: int + default: 10 + description: Number of results (max ~10 per request) + +pipeline: + - fetch: + url: https://note.com/api/v3/searches + params: + context: note + q: ${{ args.query }} + size: ${{ args.limit }} + start: "0" + + - select: data.notes + + - map: + rank: ${{ index + 1 }} + title: ${{ item.name }} + author: ${{ item.user.urlname }} + likes: ${{ item.likeCount }} + url: ${{ item.noteUrl }} + + - limit: ${{ args.limit }} + +columns: [rank, title, author, likes, url] diff --git a/src/clis/note/user.yaml b/src/clis/note/user.yaml new file mode 100644 index 00000000..b5fae86d --- /dev/null +++ b/src/clis/note/user.yaml @@ -0,0 +1,30 @@ +site: note +name: user +description: Get note.com user profile +domain: note.com +strategy: public +browser: false + +args: + username: + type: str + required: true + positional: true + description: "note.com username (urlname)" + +pipeline: + - fetch: + url: https://note.com/api/v2/creators/${{ args.username }} + + - select: data + + - map: + id: ${{ item.urlname }} + name: ${{ item.nickname }} + bio: ${{ item.profile }} + followers: ${{ item.followerCount }} + following: ${{ item.followingCount }} + articles: ${{ item.noteCount }} + url: "https://note.com/${{ item.urlname }}" + +columns: [id, name, bio, followers, following, articles, url] From 603c67ed861488c3d413c36674031fe1ea17f2c0 Mon Sep 17 00:00:00 2001 From: lhzxbsdr Date: Sat, 28 Mar 2026 04:08:30 +0800 Subject: [PATCH 4/4] docs: add Qiita and note.com adapter pages, update Bluesky and index - Add doc pages for Qiita and note.com adapters - Add search-posts to Bluesky doc page - Add Qiita and note.com to adapter index table - Add sidebar entries in VitePress config - Add entries to README.zh-CN.md adapter table Co-Authored-By: Claude Opus 4.6 (1M context) --- README.zh-CN.md | 2 ++ docs/.vitepress/config.mts | 2 ++ docs/adapters/browser/bluesky.md | 4 ++++ docs/adapters/browser/note.md | 32 ++++++++++++++++++++++++++ docs/adapters/browser/qiita.md | 31 +++++++++++++++++++++++++ docs/adapters/index.md | 2 ++ src/clis/note/search.yaml | 39 ++++++++++++++++++++------------ 7 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 docs/adapters/browser/note.md create mode 100644 docs/adapters/browser/qiita.md diff --git a/README.zh-CN.md b/README.zh-CN.md index 624760a7..a24cb9b6 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -178,6 +178,8 @@ npm install -g @jackwener/opencli@latest | **producthunt** | `posts` `today` `hot` `browse` | 公开 / 浏览器 | | **instagram** | `explore` `profile` `search` `user` `followers` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `saved` | 浏览器 | | **lobsters** | `hot` `newest` `active` `tag` | 公开 | +| **qiita** | `search` `user` `articles` | 公开 | +| **note.com** | `search` `user` `articles` | 公开 / 浏览器 | | **medium** | `feed` `search` `user` | 浏览器 | | **sinablog** | `hot` `search` `article` `user` | 浏览器 | | **substack** | `feed` `search` `publication` | 浏览器 | diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 5b4a58cd..35829deb 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -108,6 +108,8 @@ export default defineConfig({ { text: 'Wikipedia', link: '/adapters/browser/wikipedia' }, { text: 'Lobsters', link: '/adapters/browser/lobsters' }, { text: 'Steam', link: '/adapters/browser/steam' }, + { text: 'Qiita', link: '/adapters/browser/qiita' }, + { text: 'note.com', link: '/adapters/browser/note' }, ], }, { diff --git a/docs/adapters/browser/bluesky.md b/docs/adapters/browser/bluesky.md index 6e519f3b..b0063122 100644 --- a/docs/adapters/browser/bluesky.md +++ b/docs/adapters/browser/bluesky.md @@ -10,6 +10,7 @@ | `opencli bluesky user` | Recent posts from a user | | `opencli bluesky trending` | Trending topics | | `opencli bluesky search` | Search users | +| `opencli bluesky search-posts` | Search posts | | `opencli bluesky feeds` | Popular feed generators | | `opencli bluesky followers` | User's followers | | `opencli bluesky following` | Accounts a user follows | @@ -44,6 +45,9 @@ opencli bluesky thread --uri "at://did:.../app.bsky.feed.post/..." # Starter packs opencli bluesky starter-packs --handle bsky.app +# Search posts +opencli bluesky search-posts "AI agent" --limit 10 + # JSON output opencli bluesky profile --handle bsky.app -f json ``` diff --git a/docs/adapters/browser/note.md b/docs/adapters/browser/note.md new file mode 100644 index 00000000..0de8ae12 --- /dev/null +++ b/docs/adapters/browser/note.md @@ -0,0 +1,32 @@ +# note.com + +**Mode**: 🌐 / 🔐 · **Domain**: `note.com` + +## Commands + +| Command | Description | Mode | +|---------|-------------|------| +| `opencli note search ` | Search note.com articles | 🔐 Browser | +| `opencli note user ` | Get note.com user profile | 🌐 Public | +| `opencli note articles ` | List articles by a note.com user | 🌐 Public | + +## Usage Examples + +```bash +# Search articles (requires browser + login) +opencli note search "AI" --limit 5 + +# User profile +opencli note user masuyohasiri + +# User's articles +opencli note articles masuyohasiri --limit 6 + +# JSON output +opencli note user masuyohasiri -f json +``` + +## Prerequisites + +- `user` and `articles` commands use public API — no browser required +- `search` command requires the opencli Browser Bridge extension and a logged-in note.com session diff --git a/docs/adapters/browser/qiita.md b/docs/adapters/browser/qiita.md new file mode 100644 index 00000000..53e6aadc --- /dev/null +++ b/docs/adapters/browser/qiita.md @@ -0,0 +1,31 @@ +# Qiita + +**Mode**: 🌐 Public · **Domain**: `qiita.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli qiita search ` | Search Qiita articles | +| `opencli qiita user ` | Get Qiita user profile | +| `opencli qiita articles ` | List articles by a Qiita user | + +## Usage Examples + +```bash +# Search articles +opencli qiita search "ChatGPT" --limit 5 + +# User profile +opencli qiita user jnchito + +# User's articles +opencli qiita articles jnchito --limit 10 + +# JSON output +opencli qiita search "LLM" -f json +``` + +## Prerequisites + +- No browser required — uses Qiita public API v2 diff --git a/docs/adapters/index.md b/docs/adapters/index.md index 7a82f177..fbc1a24d 100644 --- a/docs/adapters/index.md +++ b/docs/adapters/index.md @@ -66,6 +66,8 @@ Run `opencli list` for the live registry. | **[wikipedia](/adapters/browser/wikipedia)** | `search` `summary` `random` `trending` | 🌐 Public | | **[lobsters](/adapters/browser/lobsters)** | `hot` `newest` `active` `tag` | 🌐 Public | | **[steam](/adapters/browser/steam)** | `top-sellers` | 🌐 Public | +| **[qiita](/adapters/browser/qiita)** | `search` `user` `articles` | 🌐 Public | +| **[note.com](/adapters/browser/note)** | `search` `user` `articles` | 🌐 / 🔐 | ## Desktop Adapters diff --git a/src/clis/note/search.yaml b/src/clis/note/search.yaml index 65453539..fac14bdc 100644 --- a/src/clis/note/search.yaml +++ b/src/clis/note/search.yaml @@ -13,26 +13,37 @@ args: limit: type: int default: 10 - description: Number of results (max ~10 per request) + description: Number of results pipeline: - - fetch: - url: https://note.com/api/v3/searches - params: - context: note - q: ${{ args.query }} - size: ${{ args.limit }} - start: "0" + - navigate: "https://note.com/search?q=${{ args.query }}&context=note&mode=search" - - select: data.notes + - evaluate: | + (async () => { + for (let i = 0; i < 20; i++) { + await new Promise(r => setTimeout(r, 500)); + if (document.querySelectorAll('a[href*="/n/n"]').length > 0) break; + } + const links = document.querySelectorAll('a[href*="/n/n"]'); + const seen = new Set(); + const results = []; + for (const a of links) { + const href = a.getAttribute('href'); + if (!href || seen.has(href)) continue; + seen.add(href); + const title = a.textContent?.trim() || ''; + if (!title || title.length < 4) continue; + const url = href.startsWith('http') ? href : 'https://note.com' + href; + results.push({ title, url }); + } + return results; + })() - map: rank: ${{ index + 1 }} - title: ${{ item.name }} - author: ${{ item.user.urlname }} - likes: ${{ item.likeCount }} - url: ${{ item.noteUrl }} + title: ${{ item.title }} + url: ${{ item.url }} - limit: ${{ args.limit }} -columns: [rank, title, author, likes, url] +columns: [rank, title, url]