channel-worker 2.5.58 → 2.5.59

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "2.5.58",
3
+ "version": "2.5.59",
4
4
  "description": "Channel Manager worker daemon — runs on remote machines to execute video pipeline jobs",
5
5
  "main": "lib/daemon.js",
6
6
  "bin": {
@@ -414,6 +414,31 @@ function safeComposerRetryError(message) {
414
414
  return err;
415
415
  }
416
416
 
417
+ // Toast "Thông báo mới" (ai đó thích/bình luận reel) nổi lên góc trái và ĂN
418
+ // CÚ CLICK: 23/08 hai lần liên tiếp bot bấm "Tiếp" thì FB nhảy sang xem reel
419
+ // cũ, composer đóng → "final description field not found". Đóng toast trước
420
+ // mỗi bước bấm; không có toast thì trả 0, rất rẻ.
421
+ async function dismissToasts(page) {
422
+ return page.evaluate(() => {
423
+ let closed = 0;
424
+ const isToast = (el) => {
425
+ const t = (el.innerText || '').slice(0, 120);
426
+ return /Thông báo mới|New notification|vừa bình luận|thích thước phim|liked your/i.test(t);
427
+ };
428
+ const roots = [...document.querySelectorAll("[role='dialog'], [role='alert'], [role='status'], div[data-visualcompletion='ignore-dynamic']")];
429
+ for (const r of roots) {
430
+ const rect = r.getBoundingClientRect();
431
+ if (rect.width < 40 || rect.height < 30) continue;
432
+ if (!isToast(r)) continue;
433
+ // Nút đóng: aria-label Đóng/Close, hoặc <div role=button> chứa dấu X.
434
+ const btn = r.querySelector("[aria-label='Đóng'], [aria-label='Close'], [aria-label*='óng thông báo']")
435
+ || [...r.querySelectorAll("[role='button'], button")].find((b) => (b.getAttribute('aria-label') || '').length < 12);
436
+ if (btn) { btn.click(); closed++; }
437
+ }
438
+ return closed;
439
+ }).catch(() => 0);
440
+ }
441
+
417
442
  async function hasVisibleReelComposer(page) {
418
443
  return page.evaluate(() => {
419
444
  for (const dlg of document.querySelectorAll("[role='dialog']")) {
@@ -2043,6 +2068,9 @@ async function runOnce({ page, payload, log }) {
2043
2068
  }
2044
2069
 
2045
2070
  // No publish yet — advance via Tiếp.
2071
+ // Đóng toast thông báo TRƯỚC: nó nổi đúng vùng thao tác và cướp cú click.
2072
+ const _toasts = await dismissToasts(page);
2073
+ if (_toasts) log('info', `[fb-pw] đóng ${_toasts} toast thông báo trước khi bấm Tiếp`);
2046
2074
  const next = await findByVerbs(nextVerbs);
2047
2075
  if (!next) {
2048
2076
  // Final "Cài đặt thước phim" step: the only action is "Đăng", which FB
@@ -2062,6 +2090,12 @@ async function runOnce({ page, payload, log }) {
2062
2090
  if (waitResult.enabled) { step--; continue; }
2063
2091
  await dumpInventory(page, log, `no-advance-${step + 1}`);
2064
2092
  await dumpFailure(page, `no-advance-${step + 1}`, log);
2093
+ // Composer biến mất (URL nhảy sang /reel/… vì toast cướp click, hoặc
2094
+ // FB tự đóng) → CHẠY LẠI cả lượt upload thay vì báo lỗi khó hiểu.
2095
+ // An toàn vì chưa hề bấm Đăng ở nhánh này.
2096
+ if (!(await hasVisibleReelComposer(page))) {
2097
+ throw safeComposerRetryError(`FB composer đóng giữa chừng (đang ở ${page.url().slice(0, 80)}) — chạy lại lượt đăng`);
2098
+ }
2065
2099
  if (!fillState.description) {
2066
2100
  throw new Error(`FB final description field not found at step ${step + 1}`);
2067
2101
  }