channel-worker 2.5.103 → 2.5.104
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 +61 -2
package/package.json
CHANGED
|
@@ -651,12 +651,21 @@ async function isCustomThumbApplied(page) {
|
|
|
651
651
|
// xong quyền riêng tư của Thước phim" → Đăng xám mãi; đứng
|
|
652
652
|
// 600s rồi "description field not found" (phụ kiện điện tử
|
|
653
653
|
// 02 10/09, kol du lịch 11/09).
|
|
654
|
+
// fbError : toast ĐEN góc trái dưới "Đã xảy ra lỗi. Việc này có thể là
|
|
655
|
+
// do lỗi kỹ thuật và chúng tôi đang khắc phục rồi." → chính
|
|
656
|
+
// Facebook hỏng và tự gỡ composer. Toast này nằm NGOÀI mọi
|
|
657
|
+
// [role=dialog] nên readComposerText không thấy — đọc bằng
|
|
658
|
+
// readPageAlerts.
|
|
654
659
|
// Thuần, test được; regex neo đầu dòng cho "Đang đăng" để không dính mô tả
|
|
655
660
|
// bài có chữ "đang đăng" giữa câu.
|
|
656
661
|
const COMPOSER_TEXT_RE = {
|
|
657
662
|
rightsCheck: /Không hoàn tất được quy trình kiểm tra bản quyền|couldn['’]t complete (?:the )?(?:rights|copyright) check/i,
|
|
658
663
|
publishing: /(?:^|\n)\s*(?:Đang đăng|Đang xuất bản|Publishing|Posting)\s*(?:\.{3}|…)?\s*(?:\n|$)/i,
|
|
659
664
|
settingsStuck: /Vui lòng đợi tải xong quyền riêng tư của Thước phim|wait (?:for|until) (?:the )?reel(?:'s)? privacy/i,
|
|
665
|
+
// ĐÒI CẢ HAI VẾ trong cùng một quãng ngắn. Chỉ "Đã xảy ra lỗi" thôi thì quá
|
|
666
|
+
// dễ trúng caption bài trên feed (hàm đọc có nhánh quét cả trang), còn cặp
|
|
667
|
+
// "lỗi … lỗi kỹ thuật/khắc phục" là đúng khuôn toast của Facebook.
|
|
668
|
+
fbError: /Đã xảy ra lỗi[\s\S]{0,160}(?:lỗi kỹ thuật|đang khắc phục)|Something went wrong[\s\S]{0,160}technical (?:error|issue|problem)/i,
|
|
660
669
|
};
|
|
661
670
|
function classifyComposerText(txt) {
|
|
662
671
|
const t = String(txt || '');
|
|
@@ -664,6 +673,7 @@ function classifyComposerText(txt) {
|
|
|
664
673
|
rightsCheck: COMPOSER_TEXT_RE.rightsCheck.test(t),
|
|
665
674
|
publishing: COMPOSER_TEXT_RE.publishing.test(t),
|
|
666
675
|
settingsStuck: COMPOSER_TEXT_RE.settingsStuck.test(t),
|
|
676
|
+
fbError: COMPOSER_TEXT_RE.fbError.test(t),
|
|
667
677
|
};
|
|
668
678
|
}
|
|
669
679
|
async function readComposerText(page) {
|
|
@@ -679,6 +689,34 @@ async function readComposerText(page) {
|
|
|
679
689
|
return out.join('\n').slice(0, 8000);
|
|
680
690
|
}).catch(() => '');
|
|
681
691
|
}
|
|
692
|
+
// Chữ trong các lớp nổi NGOÀI composer: toast, alert, status.
|
|
693
|
+
//
|
|
694
|
+
// Vì sao cần: 13/09 ba kênh (kiến 01, kenh-54, kenh-55) cùng chết ở bước lưu
|
|
695
|
+
// ảnh bìa, ảnh dump cả ba đều có TOAST ĐEN góc trái dưới "Đã xảy ra lỗi… lỗi
|
|
696
|
+
// kỹ thuật… đang khắc phục rồi" — tức Facebook tự hỏng rồi gỡ composer. Câu
|
|
697
|
+
// lỗi cũ chỉ nói "composer closed", nên mỗi lần gặp lại phải mở ảnh dump mới
|
|
698
|
+
// biết là phía FB. Toast nằm ngoài [role=dialog] nên readComposerText mù.
|
|
699
|
+
//
|
|
700
|
+
// Quét theo lớp: role=alert/status + gốc portal `ignore-dynamic` (cùng bộ chọn
|
|
701
|
+
// mà dismissToasts đã dùng). Không thấy gì thì mới đọc cả trang — an toàn vì
|
|
702
|
+
// regex fbError đòi hai vế đi liền nhau.
|
|
703
|
+
async function readPageAlerts(page) {
|
|
704
|
+
return page.evaluate(() => {
|
|
705
|
+
const visible = (el) => {
|
|
706
|
+
const r = el.getBoundingClientRect();
|
|
707
|
+
if (r.width < 8 || r.height < 8) return false;
|
|
708
|
+
const cs = getComputedStyle(el);
|
|
709
|
+
return cs.visibility !== 'hidden' && cs.display !== 'none';
|
|
710
|
+
};
|
|
711
|
+
const out = [];
|
|
712
|
+
for (const el of document.querySelectorAll("[role='alert'], [role='status'], div[data-visualcompletion='ignore-dynamic']")) {
|
|
713
|
+
if (visible(el)) out.push(el.innerText || '');
|
|
714
|
+
}
|
|
715
|
+
const picked = out.join('\n').trim();
|
|
716
|
+
return (picked || (document.body ? document.body.innerText || '' : '')).slice(0, 8000);
|
|
717
|
+
}).catch(() => '');
|
|
718
|
+
}
|
|
719
|
+
|
|
682
720
|
const PUBLISHING_WAIT_MS = 5 * 60 * 1000; // "Đang đăng": chờ tới 5 phút, không bấm lại
|
|
683
721
|
const SETTINGS_STUCK_MS = 90 * 1000; // bảng cài đặt trống quá 90s: mở lại composer
|
|
684
722
|
|
|
@@ -690,6 +728,21 @@ function safeComposerRetryError(message) {
|
|
|
690
728
|
return err;
|
|
691
729
|
}
|
|
692
730
|
|
|
731
|
+
// Composer biến mất → nói RÕ vì sao, nếu Facebook có để lại toast lỗi.
|
|
732
|
+
//
|
|
733
|
+
// GIỮ NGUYÊN cụm "composer closed after saving thumbnail" ở cuối câu: luật
|
|
734
|
+
// `composer_closed` bên api/services/PublishRetry khớp theo cụm đó. Worker lên
|
|
735
|
+
// bản mới bằng chép nóng (có hiệu lực ngay), còn API thì deploy riêng — đổi
|
|
736
|
+
// hẳn câu lỗi là lỗi này rơi vào "lỗi lạ" (trần thử lại 1 lần) cho tới khi API
|
|
737
|
+
// kịp lên. Thêm vế giải thích ở ĐẦU, không thay phần đuôi.
|
|
738
|
+
async function composerClosedError(page, log, fallbackMessage) {
|
|
739
|
+
let fbError = false;
|
|
740
|
+
try { fbError = classifyComposerText(await readPageAlerts(page)).fbError; } catch { /* đọc lỗi thì cứ dùng câu cũ */ }
|
|
741
|
+
if (!fbError) return safeComposerRetryError(fallbackMessage);
|
|
742
|
+
log('warn', '[fb-pw] Facebook hiện toast "Đã xảy ra lỗi… lỗi kỹ thuật" — chính FB hỏng rồi gỡ composer, không phải lỗi bài/tài khoản');
|
|
743
|
+
return safeComposerRetryError(`Facebook báo lỗi kỹ thuật ("Đã xảy ra lỗi… chúng tôi đang khắc phục") rồi tự gỡ trình soạn — ${fallbackMessage}`);
|
|
744
|
+
}
|
|
745
|
+
|
|
693
746
|
// 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
|
|
694
747
|
// CÚ CLICK: 23/08 hai lần liên tiếp bot bấm "Tiếp" thì FB nhảy sang xem reel
|
|
695
748
|
// cũ, composer đóng → "final description field not found". Đóng toast trước
|
|
@@ -2036,7 +2089,7 @@ async function runOnce({ page, payload, log }) {
|
|
|
2036
2089
|
// safe here because the publish branch has not run yet.
|
|
2037
2090
|
if (!(await hasVisibleReelComposer(page))) {
|
|
2038
2091
|
await dumpFailure(page, 'composer-closed-after-thumb-save', log);
|
|
2039
|
-
throw
|
|
2092
|
+
throw await composerClosedError(page, log, 'FB Reel composer closed after saving thumbnail (before publish)');
|
|
2040
2093
|
}
|
|
2041
2094
|
thumbApplied = true;
|
|
2042
2095
|
log('info', `[fb-pw] page-wall thumb — modal closed after save (retries=${retryCount})`);
|
|
@@ -2723,7 +2776,11 @@ async function runOnce({ page, payload, log }) {
|
|
|
2723
2776
|
// FB tự đóng) → CHẠY LẠI cả lượt upload thay vì báo lỗi khó hiểu.
|
|
2724
2777
|
// An toàn vì chưa hề bấm Đăng ở nhánh này.
|
|
2725
2778
|
if (!(await hasVisibleReelComposer(page))) {
|
|
2726
|
-
|
|
2779
|
+
// Câu lỗi phải chứa "composer closed … before publish": luật
|
|
2780
|
+
// `composer_closed` của PublishRetry khớp theo cụm đó. Bản cũ viết
|
|
2781
|
+
// thuần tiếng Việt nên nếu lượt trong phiên cũng hỏng thì lỗi rơi
|
|
2782
|
+
// vào "lỗi lạ" (trần thử lại 1 lần) thay vì được xếp lại 3 lần.
|
|
2783
|
+
throw await composerClosedError(page, log, `FB Reel composer closed (before publish) — đóng giữa chừng ở ${page.url().slice(0, 80)}, chạy lại lượt đăng`);
|
|
2727
2784
|
}
|
|
2728
2785
|
if (!fillState.description) {
|
|
2729
2786
|
throw new Error(`FB final description field not found at step ${step + 1}`);
|
|
@@ -3298,6 +3355,8 @@ module.exports.__testables = {
|
|
|
3298
3355
|
pickReelsTabUrl,
|
|
3299
3356
|
networkIdVerdict,
|
|
3300
3357
|
classifyComposerText,
|
|
3358
|
+
readPageAlerts,
|
|
3359
|
+
composerClosedError,
|
|
3301
3360
|
isComposerDialogSignature,
|
|
3302
3361
|
discoverReelsTabUrl,
|
|
3303
3362
|
scrapeReelTileIds,
|