channel-worker 2.5.16 → 2.5.18
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 +48 -11
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.18b-thumb-required');
|
|
287
287
|
|
|
288
288
|
page.on('dialog', (d) => { d.accept().catch(() => {}); });
|
|
289
289
|
|
|
@@ -525,7 +525,19 @@ async function run({ page, payload, log }) {
|
|
|
525
525
|
// (some FB builds only show them on the final Chia sẻ step). The
|
|
526
526
|
// helper is idempotent: it tracks per-field "done" so we don't
|
|
527
527
|
// re-fill on subsequent steps.
|
|
528
|
-
|
|
528
|
+
// FB Reels page-wall composer has ONLY one caption field ("Mô tả thước
|
|
529
|
+
// phim") — no separate Title or Tags input (those were BS-composer fields,
|
|
530
|
+
// now gone). Per product decision the reel caption = title + hashtags
|
|
531
|
+
// (the description is dropped). Hashtags are collapsed to single #tokens
|
|
532
|
+
// since FB caption hashtags can't contain spaces ("gia dung" → "#giadung").
|
|
533
|
+
const fbHashtags = (tags || [])
|
|
534
|
+
.map(t => '#' + String(t || '').trim().replace(/[#\s]+/g, ''))
|
|
535
|
+
.filter(h => h.length > 1);
|
|
536
|
+
const fbCaption = [String(title || '').trim(), fbHashtags.join(' ')]
|
|
537
|
+
.filter(Boolean).join('\n\n');
|
|
538
|
+
// Pre-mark title+tags "done" so the legacy BS title/tags probes are skipped;
|
|
539
|
+
// only the description field is filled — with fbCaption (title + hashtags).
|
|
540
|
+
const fillState = { title: true, description: false, tags: true };
|
|
529
541
|
const fillMetadata = async () => {
|
|
530
542
|
// Title (Tiêu đề thước phim). Variant-A input is shown by default in the
|
|
531
543
|
// BS composer — NO reveal click needed. Earlier `revealCandidates` clicks
|
|
@@ -677,7 +689,7 @@ async function run({ page, payload, log }) {
|
|
|
677
689
|
if (!f) continue;
|
|
678
690
|
try {
|
|
679
691
|
await f.click({ timeout: 3000 });
|
|
680
|
-
const descText = (description || title || '').toString().slice(0, 2100);
|
|
692
|
+
const descText = (fbCaption || description || title || '').toString().slice(0, 2100);
|
|
681
693
|
if (!descText) break;
|
|
682
694
|
await f.type(descText, { delay: 12 });
|
|
683
695
|
fillState.description = true;
|
|
@@ -906,6 +918,7 @@ async function run({ page, payload, log }) {
|
|
|
906
918
|
// iterations, throw with diagnostics.
|
|
907
919
|
let published = false;
|
|
908
920
|
let customThumbDone = false;
|
|
921
|
+
let thumbWaitDone = false; // poll for the thumb-edit pill at most once
|
|
909
922
|
let pubWaitDone = false; // guard: wait for a disabled "Đăng" at most once
|
|
910
923
|
for (let step = 0; step < 7 && !published; step++) {
|
|
911
924
|
await page.waitForTimeout(3000);
|
|
@@ -916,7 +929,7 @@ async function run({ page, payload, log }) {
|
|
|
916
929
|
// file picker → "Lưu"). Per user screenshots, this is the only way to
|
|
917
930
|
// attach a custom thumbnail in the Page-wall composer.
|
|
918
931
|
if (!customThumbDone && thumbPath && /^https?:\/\/(www\.)?facebook\.com\/?($|\?|#)/.test(page.url())) {
|
|
919
|
-
const
|
|
932
|
+
const findThumbBtn = () => page.evaluate(() => {
|
|
920
933
|
// Look for the thumbnail-edit button inside the REEL COMPOSER dialog
|
|
921
934
|
// only — scanning all dialogs risked matching a button on the
|
|
922
935
|
// page-wall photo composer (which would post a separate "Tin dạng
|
|
@@ -957,7 +970,20 @@ async function run({ page, payload, log }) {
|
|
|
957
970
|
}
|
|
958
971
|
return null;
|
|
959
972
|
}).catch(() => null);
|
|
973
|
+
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(); }
|
|
982
|
+
if (editBtn) log('info', '[fb-pw] thumb-edit pill appeared after wait');
|
|
983
|
+
}
|
|
984
|
+
thumbWaitDone = true;
|
|
960
985
|
|
|
986
|
+
let thumbApplied = false;
|
|
961
987
|
if (editBtn) {
|
|
962
988
|
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}` : ''})…`);
|
|
963
989
|
try {
|
|
@@ -1078,6 +1104,7 @@ async function run({ page, payload, log }) {
|
|
|
1078
1104
|
await page.waitForTimeout(1000);
|
|
1079
1105
|
}
|
|
1080
1106
|
if (modalClosed) {
|
|
1107
|
+
thumbApplied = true;
|
|
1081
1108
|
log('info', `[fb-pw] page-wall thumb — modal closed after save (retries=${retryCount})`);
|
|
1082
1109
|
} else {
|
|
1083
1110
|
log('warn', '[fb-pw] page-wall thumb — modal still open 60s after Lưu click; trying ESC + click Hủy fallback');
|
|
@@ -1099,7 +1126,16 @@ async function run({ page, payload, log }) {
|
|
|
1099
1126
|
} catch (e) {
|
|
1100
1127
|
log('warn', `[fb-pw] page-wall thumb flow failed: ${e.message.slice(0, 100)}`);
|
|
1101
1128
|
}
|
|
1102
|
-
customThumbDone =
|
|
1129
|
+
customThumbDone = thumbApplied;
|
|
1130
|
+
}
|
|
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.
|
|
1135
|
+
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');
|
|
1103
1139
|
}
|
|
1104
1140
|
}
|
|
1105
1141
|
|
|
@@ -1423,12 +1459,13 @@ async function run({ page, payload, log }) {
|
|
|
1423
1459
|
// output. (Observed on reel 1506614811005729: step 1 → click Tiếp
|
|
1424
1460
|
// → publish, the thumb-edit pill never appeared.)
|
|
1425
1461
|
if (thumbPath && !customThumbDone) {
|
|
1426
|
-
//
|
|
1427
|
-
//
|
|
1428
|
-
//
|
|
1429
|
-
// and double-
|
|
1430
|
-
//
|
|
1431
|
-
|
|
1462
|
+
// Defensive: we normally fail at the caption step (before any Tiếp)
|
|
1463
|
+
// when a required custom thumb can't be applied. If we somehow reach
|
|
1464
|
+
// here without it, refuse to publish — but BEFORE clicking Đăng, so
|
|
1465
|
+
// nothing ships and a retry can't double-post. (The v2.5.14 double-post
|
|
1466
|
+
// came from failing AFTER publish; this throw is pre-publish.)
|
|
1467
|
+
await dumpFailure(page, 'thumb-required-at-publish', log);
|
|
1468
|
+
throw new Error('Custom thumbnail required but not applied — refusing to publish with FB auto-thumb');
|
|
1432
1469
|
}
|
|
1433
1470
|
log('info', `[fb-pw] click publish "${pub.verb}" via "${pub.sel}" (step ${step + 1})`);
|
|
1434
1471
|
// Snapshot the captured-IDs list RIGHT BEFORE the publish click. The
|