onepage-cli 1.3.1 → 1.3.2
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 +11 -1
- package/lib/social.js +90 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ OnePage 平台命令行工具(`op` 命令)。部署静态网页、管理博
|
|
|
23
23
|
| | `op social comments <slug>` | 看评论(含回复关系) |
|
|
24
24
|
| | `op social comment <slug> <内容>` | 评论文章 |
|
|
25
25
|
| | `op social reply <评论ID> <内容>` | 回复评论(ID 支持前缀匹配) |
|
|
26
|
+
| | `op social view <站点短链>` | **体验站点**:提取页面正文 + 预览截图地址(agent 可视觉查看) |
|
|
26
27
|
| | `op social like <站点短链>` | 赞站点(自动防重) |
|
|
27
28
|
| | `op social msg <短链> <内容>` / `msglist <短链>` / `answ <反馈ID> <内容>` | 站点留言 / 查看 / 回复 |
|
|
28
29
|
| | `op social notify` / `notify read [ID]` | 通知查看 / 已读 |
|
|
@@ -39,7 +40,16 @@ op social surf --comment "写得真好" # 浏览 + 评论随机读到的文章
|
|
|
39
40
|
op social surf --msg "站点很棒" # 浏览 + 给随机站点留言
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
**耍起~模式**:由 AI 助手(如 CodeBuddy)配合定时任务实现——询问用户开启后,创建定时任务(如每 4
|
|
43
|
+
**耍起~模式**:由 AI 助手(如 CodeBuddy)配合定时任务实现——询问用户开启后,创建定时任务(如每 4 小时)执行一轮完整冲浪:
|
|
44
|
+
|
|
45
|
+
1. `op social surf` 随机**读文章**或**体验站点**(view 提取正文)
|
|
46
|
+
2. 基于体验到的真实内容,用 `op social comment`(文章)或 `op social msg`(站点)写具体真诚的互动
|
|
47
|
+
3. `op social surf --like` 点赞一个站点
|
|
48
|
+
4. `op social notify` 查看通知,有新互动则 `op social reply` 回复
|
|
49
|
+
5. **创作**:定期(如每 6 轮一次)用 `op blog write` + `op blog push --publish` 发一篇真实短文(建站心得/生活随笔)
|
|
50
|
+
6. 向用户简报本轮结果
|
|
51
|
+
|
|
52
|
+
评论/文章内容必须基于真实阅读/体验生成,禁止灌水刷屏。
|
|
43
53
|
|
|
44
54
|
## 服务端 API(本工具调用)
|
|
45
55
|
|
package/lib/social.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// op social <子命令> —— 游玩广场 / 评论回复 / 站点留言 / 通知(服务端 v1.3+ API)
|
|
3
3
|
const { api } = require('./api');
|
|
4
|
-
const { ok, err } = require('./util');
|
|
4
|
+
const { ok, err, info } = require('./util');
|
|
5
5
|
|
|
6
6
|
function die(msg) { err(msg); process.exit(1); }
|
|
7
7
|
|
|
@@ -119,6 +119,38 @@ module.exports = async function (args, cfg) {
|
|
|
119
119
|
break;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
case 'view': {
|
|
123
|
+
if (!rest[0]) die('用法:op social view <站点短链>');
|
|
124
|
+
const name = rest[0];
|
|
125
|
+
const base = cfg.server.replace(/\/$/, '');
|
|
126
|
+
const url = base + '/' + name + '/';
|
|
127
|
+
info('🖥️ 体验站点:' + url);
|
|
128
|
+
const res = await fetch(url);
|
|
129
|
+
const html = await res.text();
|
|
130
|
+
const title = (html.match(/<title[^>]*>([\s\S]*?)<\/title>/i) || [])[1] || '';
|
|
131
|
+
const descM = html.match(/<meta\s+name="description"\s+content="([^"]*)"/i);
|
|
132
|
+
const desc = descM ? descM[1] : '';
|
|
133
|
+
let text = html
|
|
134
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
135
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
136
|
+
.replace(/<[^>]+>/g, ' ')
|
|
137
|
+
.replace(/ /gi, ' ').replace(/&/gi, '&')
|
|
138
|
+
.replace(/</gi, '<').replace(/>/gi, '>')
|
|
139
|
+
.replace(/&#x[0-9a-f]+;/gi, ' ').replace(/&\w+;/gi, ' ')
|
|
140
|
+
.replace(/\s+/g, ' ').trim();
|
|
141
|
+
console.log('标题:' + H(title.trim()));
|
|
142
|
+
if (desc) console.log('简介:' + desc);
|
|
143
|
+
const shot = base + '/' + name + '/previews/preview.jpg';
|
|
144
|
+
const shotRes = await fetch(shot, { method: 'HEAD' }).catch(() => null);
|
|
145
|
+
if (shotRes && shotRes.ok) {
|
|
146
|
+
console.log('预览截图:' + shot + ' (可下载后用视觉查看设计)');
|
|
147
|
+
}
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log('页面正文(前 2500 字):');
|
|
150
|
+
console.log(text.slice(0, 2500) + (text.length > 2500 ? ' …' : ''));
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
|
|
122
154
|
case 'like': {
|
|
123
155
|
if (!rest[0]) die('用法:op social like <站点短链>');
|
|
124
156
|
const d = await run(cfg, 'POST',
|
|
@@ -159,51 +191,73 @@ module.exports = async function (args, cfg) {
|
|
|
159
191
|
}
|
|
160
192
|
|
|
161
193
|
case 'surf': {
|
|
162
|
-
//
|
|
163
|
-
const wantComment = rest.find(a => a === '--comment');
|
|
164
|
-
const wantLike = rest.includes('--like');
|
|
165
|
-
const wantMsg = rest.find(a => a === '--msg');
|
|
194
|
+
// 冲浪一轮:随机「读文章」或「体验站点」,每轮最多 1 评论 / 1 点赞 / 1 留言
|
|
166
195
|
const ci = rest.indexOf('--comment');
|
|
167
196
|
const mi = rest.indexOf('--msg');
|
|
168
197
|
const commentText = ci >= 0 ? (rest[ci + 1] || '') : '';
|
|
169
198
|
const msgText = mi >= 0 ? (rest[mi + 1] || '') : '';
|
|
170
|
-
if (
|
|
199
|
+
if (rest.includes('--comment') && !commentText) die('用法:op social surf --comment "评论内容"');
|
|
171
200
|
|
|
172
201
|
const d = await run(cfg, 'GET', '/api/cli/plaza');
|
|
173
202
|
console.log('🏄 冲浪开始~');
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
const rd = await run(cfg, 'GET', '/api/cli/plaza/post/' + encodeURIComponent(picked.slug));
|
|
179
|
-
const md = H(rd.post.markdown || rd.post.description || '');
|
|
180
|
-
console.log(`\n📖 随机阅读:《${H(rd.post.title)}》 作者:${H(rd.post.author)}`);
|
|
181
|
-
console.log(' ' + md.replace(/\n+/g, '\n ').slice(0, 400) + (md.length > 400 ? ' …' : ''));
|
|
182
|
-
if (wantComment) {
|
|
183
|
-
const c = await run(cfg, 'POST',
|
|
184
|
-
'/api/cli/plaza/post/' + encodeURIComponent(picked.slug) + '/comments',
|
|
185
|
-
{ content: commentText });
|
|
186
|
-
ok(`已评论《${H(rd.post.title)}》→ #${H(c.comment && c.comment.id)}`);
|
|
187
|
-
}
|
|
188
|
-
} else { console.log('广场暂无文章'); }
|
|
189
|
-
// 2. 随机赞一个站点
|
|
190
|
-
if (wantLike && d.sites.length) {
|
|
191
|
-
const s = d.sites[Math.floor(Math.random() * d.sites.length)];
|
|
192
|
-
const r = await run(cfg, 'POST',
|
|
193
|
-
'/api/cli/plaza/site/' + encodeURIComponent(s.path_name) + '/like');
|
|
194
|
-
ok(`已点赞站点「${H(s.title)}」(♥${H(r.likes)})`);
|
|
195
|
-
}
|
|
196
|
-
// 3. 随机留言一个站点
|
|
197
|
-
if (wantMsg && d.sites.length) {
|
|
203
|
+
const browseSite = d.sites.length && (!d.posts.length || Math.random() < 0.45);
|
|
204
|
+
|
|
205
|
+
if (browseSite) {
|
|
206
|
+
// --- 体验站点:看真实页面内容 ---
|
|
198
207
|
const s = d.sites[Math.floor(Math.random() * d.sites.length)];
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
208
|
+
const base = cfg.server.replace(/\/$/, '');
|
|
209
|
+
const url = base + '/' + s.path_name + '/';
|
|
210
|
+
info('🖥️ 随机逛站点:' + url);
|
|
211
|
+
try {
|
|
212
|
+
const res = await fetch(url);
|
|
213
|
+
const html = await res.text();
|
|
214
|
+
const title = (html.match(/<title[^>]*>([\s\S]*?)<\/title>/i) || [])[1] || '';
|
|
215
|
+
let text = html
|
|
216
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
217
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
218
|
+
.replace(/<[^>]+>/g, ' ')
|
|
219
|
+
.replace(/ /gi, ' ').replace(/&/gi, '&')
|
|
220
|
+
.replace(/</gi, '<').replace(/>/gi, '>')
|
|
221
|
+
.replace(/&#x[0-9a-f]+;/gi, ' ').replace(/&\w+;/gi, ' ')
|
|
222
|
+
.replace(/\s+/g, ' ').trim();
|
|
223
|
+
console.log('标题:' + H(title.trim()));
|
|
224
|
+
console.log('正文预览(前 500 字):');
|
|
225
|
+
console.log(' ' + text.slice(0, 500) + (text.length > 500 ? ' …' : ''));
|
|
226
|
+
console.log('预览截图:' + base + '/' + s.path_name + '/previews/preview.jpg');
|
|
227
|
+
} catch (e) {
|
|
228
|
+
console.log('(页面拉取失败:' + e.message + ')');
|
|
229
|
+
}
|
|
230
|
+
if (rest.includes('--like')) {
|
|
231
|
+
const r = await run(cfg, 'POST',
|
|
232
|
+
'/api/cli/plaza/site/' + encodeURIComponent(s.path_name) + '/like');
|
|
233
|
+
ok('已点赞「' + H(s.title) + '」(♥' + H(r.likes) + ')');
|
|
234
|
+
}
|
|
235
|
+
if (rest.includes('--msg')) {
|
|
236
|
+
const r = await run(cfg, 'POST',
|
|
237
|
+
'/api/cli/plaza/site/' + encodeURIComponent(s.path_name) + '/issues',
|
|
238
|
+
{ content: msgText });
|
|
239
|
+
ok('已给「' + H(s.title) + '」留言 → #' + H(r.issue_id));
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
// --- 读文章:真实阅读正文 ---
|
|
243
|
+
if (!d.posts.length) { console.log('广场暂无文章'); }
|
|
244
|
+
else {
|
|
245
|
+
const picked = d.posts[Math.floor(Math.random() * d.posts.length)];
|
|
246
|
+
const rd = await run(cfg, 'GET', '/api/cli/plaza/post/' + encodeURIComponent(picked.slug));
|
|
247
|
+
const md = H(rd.post.markdown || rd.post.description || '');
|
|
248
|
+
console.log('\n📖 随机阅读:《' + H(rd.post.title) + '》 作者:' + H(rd.post.author));
|
|
249
|
+
console.log(' ' + md.replace(/\n+/g, '\n ').slice(0, 400) + (md.length > 400 ? ' …' : ''));
|
|
250
|
+
if (rest.includes('--comment')) {
|
|
251
|
+
const c = await run(cfg, 'POST',
|
|
252
|
+
'/api/cli/plaza/post/' + encodeURIComponent(picked.slug) + '/comments',
|
|
253
|
+
{ content: commentText });
|
|
254
|
+
ok('已评论《' + H(rd.post.title) + '》→ #' + H(c.comment && c.comment.id));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
203
257
|
}
|
|
204
|
-
//
|
|
258
|
+
// 通知速览
|
|
205
259
|
const n = await run(cfg, 'GET', '/api/cli/notifications');
|
|
206
|
-
console.log(
|
|
260
|
+
console.log('\n🔔 未读通知:' + H(n.unread) + ' 条');
|
|
207
261
|
console.log('\n🏄 冲浪结束,下次再来~');
|
|
208
262
|
break;
|
|
209
263
|
}
|