publishport-opencli 1.0.31 → 1.0.32
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/cli-manifest.json +1 -1
- package/clis/xianyu/watch.js +43 -1
- package/package.json +1 -1
package/cli-manifest.json
CHANGED
|
@@ -51328,7 +51328,7 @@
|
|
|
51328
51328
|
{
|
|
51329
51329
|
"site": "xianyu",
|
|
51330
51330
|
"name": "watch",
|
|
51331
|
-
"description": "
|
|
51331
|
+
"description": "闲鱼私信监听:旁听网页版 IM 自己的 WebSocket 推送,一有新消息就读已打开的会话列表,按 NDJSON 逐条输出",
|
|
51332
51332
|
"access": "read",
|
|
51333
51333
|
"domain": "www.goofish.com",
|
|
51334
51334
|
"strategy": "cookie",
|
package/clis/xianyu/watch.js
CHANGED
|
@@ -1 +1,43 @@
|
|
|
1
|
-
import{registerWatch as
|
|
1
|
+
import{AuthRequiredError as m,CommandExecutionError as u}from"@jackwener/opencli/errors";import{registerWatch as w}from"../_shared/watch.js";import{buildChatUrl as _,buildInboxUrl as o,requireEvaluateObject as p}from"./im.js";const g=/"lwp"\s*:\s*"\/s\//,y=[300,700,1000,1500],l=1e4,S=`
|
|
2
|
+
(() => {
|
|
3
|
+
const rows = Array.from(document.querySelectorAll('#conv-list-scrollable [class*="conversation-item"]'));
|
|
4
|
+
const sessions = [];
|
|
5
|
+
for (const row of rows) {
|
|
6
|
+
const fk = Object.keys(row).find((k) => k.startsWith('__reactFiber'));
|
|
7
|
+
let f = fk ? row[fk] : null;
|
|
8
|
+
let info = null;
|
|
9
|
+
for (let d = 0; f && d < 25; d++, f = f.return) {
|
|
10
|
+
const p = f.memoizedProps;
|
|
11
|
+
if (p && p.sessionInfo) { info = p.sessionInfo; break; }
|
|
12
|
+
}
|
|
13
|
+
if (!info) continue;
|
|
14
|
+
const summary = info.summary || {};
|
|
15
|
+
const lm = summary.latestMessage || {};
|
|
16
|
+
const c = lm.content || {};
|
|
17
|
+
const item = info.itemInfo || {};
|
|
18
|
+
sessions.push({
|
|
19
|
+
session_id: String(info.sessionId || ''),
|
|
20
|
+
session_type: info.sessionType,
|
|
21
|
+
peer_user_id: String((info.userInfo && info.userInfo.userId) || ''),
|
|
22
|
+
peer_name: String((lm.reminder && lm.reminder.title) || (info.userInfo && (info.userInfo.fishNick || info.userInfo.nick)) || ''),
|
|
23
|
+
item_id: String(item.itemId || ''),
|
|
24
|
+
item_title: String(item.title || ''),
|
|
25
|
+
price: String(item.price || ''),
|
|
26
|
+
seller_id: String((item.sellerInfo && item.sellerInfo.userId) || ''),
|
|
27
|
+
sender_id: String((lm.senderInfo && lm.senderInfo.userId) || ''),
|
|
28
|
+
message_id: String(lm.messageId || ''),
|
|
29
|
+
content_type: c.contentType,
|
|
30
|
+
text: String((c.text && c.text.text) || summary.summaryContent || ''),
|
|
31
|
+
ts: Number(lm.timeStamp || summary.timeStamp || 0),
|
|
32
|
+
unread: Number(info.unread || 0),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const bodyText = rows.length ? '' : (document.body ? document.body.innerText : '');
|
|
36
|
+
return {
|
|
37
|
+
rows: rows.length,
|
|
38
|
+
sessions,
|
|
39
|
+
requiresAuth: /请先登录|登录后/.test(bodyText),
|
|
40
|
+
blocked: /验证码|安全验证|异常访问/.test(bodyText),
|
|
41
|
+
};
|
|
42
|
+
})()
|
|
43
|
+
`;async function a(t){const s=p(await t.evaluate(S),"watch sessions");if(!s.rows&&s.requiresAuth)throw new m("www.goofish.com","Xianyu IM requires a logged-in browser session");if(!s.rows&&s.blocked)throw new m("www.goofish.com","Xianyu IM is blocked by verification or risk control");if(s.rows&&!s.sessions.length)throw new u("闲鱼会话列表渲染出来了,但行上读不到 sessionInfo:页面结构可能改版了");return s}function c(t,s){const n=[];for(const e of t){if(!e.message_id||!e.peer_user_id)continue;const i=e.sender_id===e.peer_user_id;if(!i&&!s?.includeOwn)continue;n.push({event:"dm",id:e.message_id,ts:e.ts,conversation_id:e.session_id,sender:{id:e.sender_id,name:i?e.peer_name:""},text:e.text,url:e.item_id?_(e.item_id,e.peer_user_id):o(),raw:{session_id:e.session_id,session_type:e.session_type,peer_user_id:e.peer_user_id,item_id:e.item_id,item_title:e.item_title,price:e.price,seller_id:e.seller_id,content_type:e.content_type,unread_count:e.unread,from_peer:i}})}return n}function d(t){return t.map((s)=>`${s.session_id}:${s.message_id}`).join("|")}w({site:"xianyu",name:"watch",domain:"www.goofish.com",description:"闲鱼私信监听:旁听网页版 IM 自己的 WebSocket 推送,一有新消息就读已打开的会话列表,按 NDJSON 逐条输出",watchUrl:o(),pattern:"wss-goofish.dingtalk.com",parse:async(t,s)=>{if(!g.test(String(t?.responsePreview??"")))return null;const n=Number(t?.timestamp??0);if(n&&s.state.readStartedAt&&n<s.state.readStartedAt)return null;s.state.readStartedAt=Date.now();const e=s.state.fingerprint;let i=null;for(const r of y){await new Promise((f)=>setTimeout(f,r));i=await a(s.page);if(d(i.sessions)!==e)break}s.state.fingerprint=d(i.sessions);return c(i.sessions,s)},reconcile:async(t,s)=>{const n=await(t.getCurrentUrl?t.getCurrentUrl().catch(()=>""):Promise.resolve(""));if(!/https:\/\/www\.goofish\.com\/im\b/.test(String(n||"")))await t.goto(o());const e=Date.now()+l;let i=await a(t);while(!i.rows&&Date.now()<e){await new Promise((r)=>setTimeout(r,500));i=await a(t)}if(!i.rows)throw new u(`闲鱼会话列表 ${l/1000} 秒内没有渲染出来(收件箱为空,或页面没加载完)`);s.state.fingerprint=d(i.sessions);return c(i.sessions,s)}});
|