channel-worker 2.5.112 → 2.5.113
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/package.json
CHANGED
|
@@ -25,6 +25,25 @@
|
|
|
25
25
|
const { assertAccountUsable, readPublishBlock } = require('./lib/fb-guard');
|
|
26
26
|
const { humanClick, humanType, pause, randInt } = require('./lib/human');
|
|
27
27
|
|
|
28
|
+
// Chụp màn hình lúc trượt — mượn của upload_facebook, nhưng require MUỘN và có
|
|
29
|
+
// đường lùi.
|
|
30
|
+
//
|
|
31
|
+
// Vì sao không require ở đầu file: `lib/playwright-runner` chỉ xoá require.cache
|
|
32
|
+
// của ĐÚNG script được gọi. Chép nóng cả hai file vào máy thì bản
|
|
33
|
+
// comment_facebook mới được nạp lại ngay, còn upload_facebook có thể vẫn là bản
|
|
34
|
+
// CŨ còn nằm trong cache từ lượt đăng trước — bản cũ chưa export `dumpFailure`,
|
|
35
|
+
// require ở đầu file là cả script chết ngay dòng đầu. Chụp được ảnh thì tốt,
|
|
36
|
+
// không chụp được thì thôi, đừng vì nó mà hỏng cả lượt thả bình luận.
|
|
37
|
+
async function dumpFailure(page, tag, log) {
|
|
38
|
+
try {
|
|
39
|
+
const f = require('./upload_facebook').__testables?.dumpFailure;
|
|
40
|
+
if (typeof f === 'function') await f(page, tag, log);
|
|
41
|
+
else log('info', '[fb-cmt] bản upload_facebook đang nạp chưa có dumpFailure — bỏ qua bước chụp màn hình');
|
|
42
|
+
} catch (e) {
|
|
43
|
+
log('info', `[fb-cmt] không chụp được màn hình: ${String(e.message || e).slice(0, 80)}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
28
47
|
const NAV_TIMEOUT_MS = 45_000;
|
|
29
48
|
// Bình luận hiện ra gần như tức thì, nhưng lượt đầu sau khi mở bài thì Facebook
|
|
30
49
|
// còn đang dựng khung bình luận. 20 giây là dư cho trường hợp chậm nhất đo được
|
|
@@ -94,6 +113,34 @@ async function openCommentsIfNeeded(page, log) {
|
|
|
94
113
|
// Facebook đặt tên tác giả ngay trong aria-label của khối bình luận
|
|
95
114
|
// ("Bình luận của <Tên>" / "Comment by <Name>") — đọc thẳng ở đó chắc hơn dò
|
|
96
115
|
// anchor đầu tiên, vì trong khối còn có link tới bài, tới trang được nhắc tên.
|
|
116
|
+
// ĐẾM số chỗ trên trang có chứa chuỗi link, BỎ QUA ô soạn.
|
|
117
|
+
//
|
|
118
|
+
// Đây là cách xác minh chắc hơn hẳn việc dò cấu trúc bình luận: mình đo TRƯỚC
|
|
119
|
+
// khi gõ và ĐO LẠI sau khi gửi, thấy tăng lên là bình luận đã lên. Không cần
|
|
120
|
+
// biết Facebook dựng khung bình luận bằng thẻ gì, cũng không vỡ khi họ đổi.
|
|
121
|
+
//
|
|
122
|
+
// Vì sao phải đổi (15/09): bản đầu đòi khối bình luận mang nhãn
|
|
123
|
+
// `aria-label="Bình luận của <Tên>"` — đó là cấu trúc bài trên BẢNG TIN. Trang
|
|
124
|
+
// reel dựng khác, nên 5/5 lượt thả thật đều báo "không đọc lại thấy" trong khi
|
|
125
|
+
// chủ tịch mở bài ra thì bình luận NẰM ĐÓ. Suýt nữa thì mỗi bài hai bình luận
|
|
126
|
+
// vì nút hiện "Thả lại".
|
|
127
|
+
async function countLinkOnPage(page, link) {
|
|
128
|
+
return page.evaluate((needle) => {
|
|
129
|
+
let n = 0;
|
|
130
|
+
const walk = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
|
131
|
+
while (walk.nextNode()) {
|
|
132
|
+
const t = walk.currentNode;
|
|
133
|
+
if (!t.nodeValue || !t.nodeValue.includes(needle)) continue;
|
|
134
|
+
// Chữ mình vừa gõ trong ô soạn không tính.
|
|
135
|
+
if (t.parentElement && t.parentElement.closest("[contenteditable='true']")) continue;
|
|
136
|
+
n++;
|
|
137
|
+
}
|
|
138
|
+
return n;
|
|
139
|
+
}, link).catch(() => -1);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Cố lấy TÊN người bình luận + permalink. Best-effort thuần: không lấy được thì
|
|
143
|
+
// để trống chứ KHÔNG coi là thất bại — xác minh đã do phép đếm ở trên lo.
|
|
97
144
|
async function findPostedComment(page, link) {
|
|
98
145
|
return page.evaluate((needle) => {
|
|
99
146
|
const out = { found: false, author: '', comment_url: '' };
|
|
@@ -121,16 +168,22 @@ async function findPostedComment(page, link) {
|
|
|
121
168
|
}, link).catch(() => ({ found: false, author: '', comment_url: '' }));
|
|
122
169
|
}
|
|
123
170
|
|
|
124
|
-
async function waitForPostedComment(page, link, log, timeoutMs = VERIFY_TIMEOUT_MS) {
|
|
171
|
+
async function waitForPostedComment(page, link, log, timeoutMs = VERIFY_TIMEOUT_MS, baseline = 0) {
|
|
125
172
|
const deadline = Date.now() + timeoutMs;
|
|
126
|
-
let
|
|
173
|
+
let meta = { found: false, author: '', comment_url: '' };
|
|
127
174
|
while (Date.now() < deadline) {
|
|
128
|
-
|
|
129
|
-
|
|
175
|
+
const n = await countLinkOnPage(page, link);
|
|
176
|
+
// Tăng so với lúc trước khi gõ = bình luận đã lên. Đây mới là bằng chứng;
|
|
177
|
+
// tên tác giả và permalink chỉ là thông tin kèm theo.
|
|
178
|
+
if (n > baseline) {
|
|
179
|
+
meta = await findPostedComment(page, link);
|
|
180
|
+
return { ...meta, found: true, count: n };
|
|
181
|
+
}
|
|
130
182
|
await page.waitForTimeout(1200);
|
|
131
183
|
}
|
|
132
|
-
|
|
133
|
-
|
|
184
|
+
const n = await countLinkOnPage(page, link);
|
|
185
|
+
log('warn', `[fb-cmt] hết ${Math.round(timeoutMs / 1000)}s: số chỗ có link vẫn là ${n} (trước khi gõ ${baseline}) — chưa thấy bình luận lên`);
|
|
186
|
+
return { ...meta, found: false, count: n };
|
|
134
187
|
}
|
|
135
188
|
|
|
136
189
|
// ─── ghim ───────────────────────────────────────────────────────────────────
|
|
@@ -217,6 +270,11 @@ async function run({ page, payload = {}, log }) {
|
|
|
217
270
|
throw new Error(`Không tìm thấy ô soạn bình luận trên ${postUrl} (đã thử ${BOX_SELECTORS.length} nhãn) — nhiều khả năng bài tắt bình luận hoặc Facebook đổi giao diện`);
|
|
218
271
|
}
|
|
219
272
|
|
|
273
|
+
// Đo NỀN trước khi gõ: link có thể đã nằm sẵn trong caption, hoặc bài đã
|
|
274
|
+
// được thả bình luận từ lượt trước.
|
|
275
|
+
const baseline = Math.max(await countLinkOnPage(page, link), 0);
|
|
276
|
+
if (baseline > 0) log('info', `[fb-cmt] link đã xuất hiện ${baseline} chỗ trên bài từ trước — chỉ tính là xong khi tăng thêm`);
|
|
277
|
+
|
|
220
278
|
await box.scrollIntoViewIfNeeded({ timeout: 5000 }).catch(() => {});
|
|
221
279
|
await humanClick(page, box).catch(async () => { await box.click({ timeout: 5000 }); });
|
|
222
280
|
await pause(page, 900);
|
|
@@ -240,9 +298,12 @@ async function run({ page, payload = {}, log }) {
|
|
|
240
298
|
throw new Error(`FB_COMMENT_RATE_LIMITED: Facebook chặn bình luận vì tần suất/nghi spam — bình luận KHÔNG được nhận. Chuỗi bắt được: "${block}". Dừng thả link trên kênh này cho tới khi người kiểm tra.`);
|
|
241
299
|
}
|
|
242
300
|
|
|
243
|
-
const found = await waitForPostedComment(page, link, log);
|
|
301
|
+
const found = await waitForPostedComment(page, link, log, VERIFY_TIMEOUT_MS, baseline);
|
|
244
302
|
if (!found.found) {
|
|
245
303
|
await assertAccountUsable(page, log);
|
|
304
|
+
// Chụp lại màn hình: lần trước trượt xác minh mà không có gì để soi, phải
|
|
305
|
+
// đợi chủ tịch tự mở Facebook mới biết bình luận có lên hay không.
|
|
306
|
+
await dumpFailure(page, 'cmt-verify', log);
|
|
246
307
|
// KHÔNG ném lỗi kiểu "có thể đã thả": trả về verified=false để API ghi
|
|
247
308
|
// 'failed' kèm nguyên văn. Ném lỗi ở đây thì lượt chạy lại sẽ gõ thêm một
|
|
248
309
|
// bình luận nữa, mà bình luận trước có thể đã nằm đó rồi.
|
|
@@ -268,4 +329,4 @@ async function run({ page, payload = {}, log }) {
|
|
|
268
329
|
}
|
|
269
330
|
|
|
270
331
|
module.exports = { run };
|
|
271
|
-
module.exports.__testables = { findPostedComment, findCommentBox, BOX_SELECTORS, sel };
|
|
332
|
+
module.exports.__testables = { findPostedComment, countLinkOnPage, waitForPostedComment, findCommentBox, BOX_SELECTORS, sel };
|
|
@@ -3425,6 +3425,9 @@ module.exports = { run };
|
|
|
3425
3425
|
// Exposed so the overlay-click escalation can be exercised against a synthetic
|
|
3426
3426
|
// page (toast covering the CTA) without driving the whole upload flow.
|
|
3427
3427
|
module.exports.__testables = {
|
|
3428
|
+
// Dùng chung cho comment_facebook: script nào trượt giữa chừng cũng cần chụp
|
|
3429
|
+
// lại màn hình, viết bản thứ hai là sớm muộn hai bên lệch nhau.
|
|
3430
|
+
dumpFailure,
|
|
3428
3431
|
resilientClick,
|
|
3429
3432
|
confirmPublishDialog,
|
|
3430
3433
|
diffNewReelIds,
|