channel-worker 2.5.18 → 2.5.20

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.18",
3
+ "version": "2.5.20",
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": {
@@ -283,7 +283,7 @@ async function run({ page, payload, log }) {
283
283
  } = payload || {};
284
284
  if (!video_url) throw new Error('No video_url provided');
285
285
 
286
- log('info', '[fb-pw] selectors version=2026.06.18b-thumb-required');
286
+ log('info', '[fb-pw] selectors version=2026.06.19a-thumb-advance');
287
287
 
288
288
  page.on('dialog', (d) => { d.accept().catch(() => {}); });
289
289
 
@@ -510,11 +510,41 @@ async function run({ page, payload, log }) {
510
510
  throw new Error('FB Reels modal: "Thêm video"/"Tải lên" trigger not found — could not start video upload');
511
511
  }
512
512
 
513
- // 4) Wait for the video to finish processing on FB's side before we can
514
- // fill the caption + advance. FB shows a progress indicator and only
515
- // enables the "Tiếp" button once upload + thumbnail extraction is done.
516
- log('info', '[fb-pw] waiting for video upload to process (up to 60s)…');
517
- await page.waitForTimeout(30000); // FB processes 10-60s for short Reels
513
+ // 4) Wait for FB to finish processing the uploaded video before filling the
514
+ // caption + advancing. FB disables "Tiếp" (and hides the caption field)
515
+ // until upload + frame-extraction is done; processing time scales with
516
+ // video size/length. Instead of a blind fixed sleep (wasted idle for
517
+ // small clips, too short for big ones), POLL for an ENABLED "Tiếp" —
518
+ // proceed the instant it's ready, but give large clips up to 120s.
519
+ log('info', '[fb-pw] waiting for FB to finish processing the video…');
520
+ const procT0 = Date.now();
521
+ const procDeadline = procT0 + 120_000;
522
+ await page.waitForTimeout(2500); // let the upload register first
523
+ let procReady = false;
524
+ while (Date.now() < procDeadline) {
525
+ procReady = await page.evaluate(() => {
526
+ const dlgs = document.querySelectorAll("[role='dialog']");
527
+ const roots = dlgs.length ? Array.from(dlgs) : [document];
528
+ const verbs = ['Tiếp', 'Tiếp theo', 'Next', 'Continue'];
529
+ for (const root of roots) {
530
+ for (const el of root.querySelectorAll("button, [role='button']")) {
531
+ const t = (el.innerText || '').trim();
532
+ if (!verbs.includes(t)) continue;
533
+ const r = el.getBoundingClientRect();
534
+ if (r.width < 8 || r.height < 8) continue;
535
+ const cs = getComputedStyle(el);
536
+ if (cs.visibility === 'hidden' || cs.display === 'none') continue;
537
+ if (el.getAttribute('aria-disabled') === 'true' || el.disabled) continue;
538
+ return true; // an enabled Tiếp/Next → processing done, can advance
539
+ }
540
+ }
541
+ return false;
542
+ }).catch(() => false);
543
+ if (procReady) break;
544
+ await page.waitForTimeout(2500);
545
+ }
546
+ if (procReady) log('info', `[fb-pw] video processed in ~${Math.round((Date.now() - procT0) / 1000)}s — caption step ready`);
547
+ else log('warn', '[fb-pw] processing wait hit 120s cap — proceeding (Tiếp click auto-waits anyway)');
518
548
 
519
549
  // 5) Fill metadata. FB Reels has THREE separate fields (verified visually
520
550
  // by user — different from how YT lumps everything into title + desc):
@@ -918,7 +948,6 @@ async function run({ page, payload, log }) {
918
948
  // iterations, throw with diagnostics.
919
949
  let published = false;
920
950
  let customThumbDone = false;
921
- let thumbWaitDone = false; // poll for the thumb-edit pill at most once
922
951
  let pubWaitDone = false; // guard: wait for a disabled "Đăng" at most once
923
952
  for (let step = 0; step < 7 && !published; step++) {
924
953
  await page.waitForTimeout(3000);
@@ -971,17 +1000,18 @@ async function run({ page, payload, log }) {
971
1000
  return null;
972
1001
  }).catch(() => null);
973
1002
  let editBtn = await findThumbBtn();
974
- // The "Chỉnh sửa hình thu nhỏ" pill only appears AFTER FB finishes
975
- // processing the uploaded video (frame extraction). For larger clips
976
- // that lags past the 30s upload-wait, so a single check often misses it.
977
- // Poll once (up to 75s) for it before giving up.
978
- if (!editBtn && !thumbWaitDone) {
979
- log('info', '[fb-pw] thumb-edit pill not visible yet waiting for video processing (up to 75s)…');
980
- const tdl = Date.now() + 75_000;
981
- while (!editBtn && Date.now() < tdl) { await page.waitForTimeout(4000); editBtn = await findThumbBtn(); }
1003
+ // The "Chỉnh sửa hình thu nhỏ" pill appears AFTER FB finishes processing
1004
+ // the video AND, on the Page-wall composer, only on a LATER step (the
1005
+ // cover/caption step AFTER clicking "Tiếp" from the video step) NOT on
1006
+ // the first video step. So poll briefly on THIS step; if it never shows,
1007
+ // fall through to click "Tiếp" and look again on the next step. Per-step
1008
+ // (not one-time) so the pill is caught on whichever step it renders.
1009
+ if (!editBtn) {
1010
+ log('info', '[fb-pw] thumb-edit pill not visible on this step polling up to 18s…');
1011
+ const tdl = Date.now() + 18_000;
1012
+ while (!editBtn && Date.now() < tdl) { await page.waitForTimeout(3000); editBtn = await findThumbBtn(); }
982
1013
  if (editBtn) log('info', '[fb-pw] thumb-edit pill appeared after wait');
983
1014
  }
984
- thumbWaitDone = true;
985
1015
 
986
1016
  let thumbApplied = false;
987
1017
  if (editBtn) {
@@ -1128,14 +1158,14 @@ async function run({ page, payload, log }) {
1128
1158
  }
1129
1159
  customThumbDone = thumbApplied;
1130
1160
  }
1131
- // The idea HAS a thumbnail it is REQUIRED. If the pill never showed
1132
- // (after the wait) or applying it failed, REFUSE to publish with FB's
1133
- // auto-thumb. Fail HERE at the caption step, BEFORE any "Tiếp"/publish
1134
- // so nothing ships and a retry can't double-post.
1161
+ // Pill not on THIS step (e.g. the video step before "Tiếp", or the
1162
+ // cover step hasn't rendered yet). Do NOT hard-fail here click "Tiếp"
1163
+ // to advance and retry the thumb flow on the next step. The pre-publish
1164
+ // check below (before clicking "Đăng") hard-fails if the thumb was never
1165
+ // applied across ANY step, so nothing ships with FB's auto-thumb and a
1166
+ // retry can't double-post.
1135
1167
  if (!customThumbDone) {
1136
- await dumpInventory(page, log, 'thumb-required-missing');
1137
- await dumpFailure(page, 'thumb-required-missing', log);
1138
- throw new Error('Custom thumbnail required but could not be applied (FB "Chỉnh sửa hình thu nhỏ" not available, or upload/save failed) — refusing to publish with FB auto-thumb');
1168
+ log('info', '[fb-pw] thumb-edit pill not on this step yet — advancing via "Tiếp" to retry on the next step');
1139
1169
  }
1140
1170
  }
1141
1171