channel-worker 2.5.17 → 2.5.19
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 +1 -1
- package/scripts/upload_facebook.js +69 -14
package/package.json
CHANGED
|
@@ -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.
|
|
286
|
+
log('info', '[fb-pw] selectors version=2026.06.18c-proc-wait');
|
|
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
|
|
514
|
-
//
|
|
515
|
-
//
|
|
516
|
-
|
|
517
|
-
|
|
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,6 +948,7 @@ async function run({ page, payload, log }) {
|
|
|
918
948
|
// iterations, throw with diagnostics.
|
|
919
949
|
let published = false;
|
|
920
950
|
let customThumbDone = false;
|
|
951
|
+
let thumbWaitDone = false; // poll for the thumb-edit pill at most once
|
|
921
952
|
let pubWaitDone = false; // guard: wait for a disabled "Đăng" at most once
|
|
922
953
|
for (let step = 0; step < 7 && !published; step++) {
|
|
923
954
|
await page.waitForTimeout(3000);
|
|
@@ -928,7 +959,7 @@ async function run({ page, payload, log }) {
|
|
|
928
959
|
// file picker → "Lưu"). Per user screenshots, this is the only way to
|
|
929
960
|
// attach a custom thumbnail in the Page-wall composer.
|
|
930
961
|
if (!customThumbDone && thumbPath && /^https?:\/\/(www\.)?facebook\.com\/?($|\?|#)/.test(page.url())) {
|
|
931
|
-
const
|
|
962
|
+
const findThumbBtn = () => page.evaluate(() => {
|
|
932
963
|
// Look for the thumbnail-edit button inside the REEL COMPOSER dialog
|
|
933
964
|
// only — scanning all dialogs risked matching a button on the
|
|
934
965
|
// page-wall photo composer (which would post a separate "Tin dạng
|
|
@@ -969,7 +1000,20 @@ async function run({ page, payload, log }) {
|
|
|
969
1000
|
}
|
|
970
1001
|
return null;
|
|
971
1002
|
}).catch(() => null);
|
|
1003
|
+
let editBtn = await findThumbBtn();
|
|
1004
|
+
// The "Chỉnh sửa hình thu nhỏ" pill only appears AFTER FB finishes
|
|
1005
|
+
// processing the uploaded video (frame extraction). For larger clips
|
|
1006
|
+
// that lags past the 30s upload-wait, so a single check often misses it.
|
|
1007
|
+
// Poll once (up to 75s) for it before giving up.
|
|
1008
|
+
if (!editBtn && !thumbWaitDone) {
|
|
1009
|
+
log('info', '[fb-pw] thumb-edit pill not visible yet — waiting for video processing (up to 75s)…');
|
|
1010
|
+
const tdl = Date.now() + 75_000;
|
|
1011
|
+
while (!editBtn && Date.now() < tdl) { await page.waitForTimeout(4000); editBtn = await findThumbBtn(); }
|
|
1012
|
+
if (editBtn) log('info', '[fb-pw] thumb-edit pill appeared after wait');
|
|
1013
|
+
}
|
|
1014
|
+
thumbWaitDone = true;
|
|
972
1015
|
|
|
1016
|
+
let thumbApplied = false;
|
|
973
1017
|
if (editBtn) {
|
|
974
1018
|
log('info', `[fb-pw] page-wall thumb — opening "Chỉnh sửa hình thu nhỏ" modal (via=${editBtn.via}, aria="${editBtn.aria}", text="${editBtn.text}"${editBtn.size ? `, size=${editBtn.size}` : ''})…`);
|
|
975
1019
|
try {
|
|
@@ -1090,6 +1134,7 @@ async function run({ page, payload, log }) {
|
|
|
1090
1134
|
await page.waitForTimeout(1000);
|
|
1091
1135
|
}
|
|
1092
1136
|
if (modalClosed) {
|
|
1137
|
+
thumbApplied = true;
|
|
1093
1138
|
log('info', `[fb-pw] page-wall thumb — modal closed after save (retries=${retryCount})`);
|
|
1094
1139
|
} else {
|
|
1095
1140
|
log('warn', '[fb-pw] page-wall thumb — modal still open 60s after Lưu click; trying ESC + click Hủy fallback');
|
|
@@ -1111,7 +1156,16 @@ async function run({ page, payload, log }) {
|
|
|
1111
1156
|
} catch (e) {
|
|
1112
1157
|
log('warn', `[fb-pw] page-wall thumb flow failed: ${e.message.slice(0, 100)}`);
|
|
1113
1158
|
}
|
|
1114
|
-
customThumbDone =
|
|
1159
|
+
customThumbDone = thumbApplied;
|
|
1160
|
+
}
|
|
1161
|
+
// The idea HAS a thumbnail → it is REQUIRED. If the pill never showed
|
|
1162
|
+
// (after the wait) or applying it failed, REFUSE to publish with FB's
|
|
1163
|
+
// auto-thumb. Fail HERE — at the caption step, BEFORE any "Tiếp"/publish
|
|
1164
|
+
// — so nothing ships and a retry can't double-post.
|
|
1165
|
+
if (!customThumbDone) {
|
|
1166
|
+
await dumpInventory(page, log, 'thumb-required-missing');
|
|
1167
|
+
await dumpFailure(page, 'thumb-required-missing', log);
|
|
1168
|
+
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');
|
|
1115
1169
|
}
|
|
1116
1170
|
}
|
|
1117
1171
|
|
|
@@ -1435,12 +1489,13 @@ async function run({ page, payload, log }) {
|
|
|
1435
1489
|
// output. (Observed on reel 1506614811005729: step 1 → click Tiếp
|
|
1436
1490
|
// → publish, the thumb-edit pill never appeared.)
|
|
1437
1491
|
if (thumbPath && !customThumbDone) {
|
|
1438
|
-
//
|
|
1439
|
-
//
|
|
1440
|
-
//
|
|
1441
|
-
// and double-
|
|
1442
|
-
//
|
|
1443
|
-
|
|
1492
|
+
// Defensive: we normally fail at the caption step (before any Tiếp)
|
|
1493
|
+
// when a required custom thumb can't be applied. If we somehow reach
|
|
1494
|
+
// here without it, refuse to publish — but BEFORE clicking Đăng, so
|
|
1495
|
+
// nothing ships and a retry can't double-post. (The v2.5.14 double-post
|
|
1496
|
+
// came from failing AFTER publish; this throw is pre-publish.)
|
|
1497
|
+
await dumpFailure(page, 'thumb-required-at-publish', log);
|
|
1498
|
+
throw new Error('Custom thumbnail required but not applied — refusing to publish with FB auto-thumb');
|
|
1444
1499
|
}
|
|
1445
1500
|
log('info', `[fb-pw] click publish "${pub.verb}" via "${pub.sel}" (step ${step + 1})`);
|
|
1446
1501
|
// Snapshot the captured-IDs list RIGHT BEFORE the publish click. The
|