channel-worker 2.5.31 → 2.5.33
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/warmup_facebook.js +63 -18
package/package.json
CHANGED
|
@@ -140,8 +140,20 @@ async function focusFbSearch(page, log) {
|
|
|
140
140
|
if (box) {
|
|
141
141
|
try {
|
|
142
142
|
await box.click({ timeout: 2500 });
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
// CLEAR the previous keyword first. FB's search is a React-controlled
|
|
144
|
+
// input — Ctrl+A+Backspace didn't reset its value (keywords appended:
|
|
145
|
+
// "kw1kw2"). locator.fill('') dispatches the input events React needs,
|
|
146
|
+
// reliably emptying it; verify + fall back to mass-Backspace.
|
|
147
|
+
await box.fill('').catch(() => {});
|
|
148
|
+
let cur = await box.evaluate(el => (el.value != null ? el.value : (el.textContent || ''))).catch(() => '');
|
|
149
|
+
if (cur && cur.trim()) {
|
|
150
|
+
await page.keyboard.press('End').catch(() => {});
|
|
151
|
+
for (let i = 0; i < cur.length + 8; i++) await page.keyboard.press('Backspace').catch(() => {});
|
|
152
|
+
cur = await box.evaluate(el => (el.value != null ? el.value : (el.textContent || ''))).catch(() => '');
|
|
153
|
+
}
|
|
154
|
+
if (cur && cur.trim()) { log('info', `[warmup-fb] search box not fully cleared (still "${cur.slice(0, 20)}") — typing anyway`); }
|
|
155
|
+
// Re-focus so the subsequent human-typing lands in the box.
|
|
156
|
+
await box.click({ timeout: 2000 }).catch(() => {});
|
|
145
157
|
return true;
|
|
146
158
|
} catch {}
|
|
147
159
|
}
|
|
@@ -247,9 +259,30 @@ async function readVideoState(page) {
|
|
|
247
259
|
}).catch(() => null);
|
|
248
260
|
}
|
|
249
261
|
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
262
|
+
// Is the currently-open reel/video SPONSORED (an ad)? Looks for a visible
|
|
263
|
+
// "Được tài trợ"/"Sponsored" label in the viewport (the reel viewer is
|
|
264
|
+
// fullscreen, so a visible sponsored tag means THIS reel is the ad). Best-effort.
|
|
265
|
+
async function isSponsoredReel(page) {
|
|
266
|
+
return page.evaluate(() => {
|
|
267
|
+
const re = /^(được tài trợ|sponsored|tài trợ)$/i;
|
|
268
|
+
for (const el of document.querySelectorAll("a, span, div")) {
|
|
269
|
+
const t = (el.innerText || el.textContent || '').trim();
|
|
270
|
+
if (!re.test(t)) continue;
|
|
271
|
+
if (el.offsetParent === null) continue;
|
|
272
|
+
const r = el.getBoundingClientRect();
|
|
273
|
+
if (r.width > 0 && r.height > 0 && r.top >= 0 && r.top < window.innerHeight && r.left < window.innerWidth) return true;
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}).catch(() => false);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Watch whatever reel/video is currently open (after clicking a result). Rules:
|
|
280
|
+
// - SKIP sponsored/ad reels entirely (don't count) — user: ads shouldn't count.
|
|
281
|
+
// - Count ONLY seconds the video actually ADVANCES — a frozen/buffering video
|
|
282
|
+
// no longer accrues watch time (user: "video đơ vẫn đếm giây"). Loop wrap
|
|
283
|
+
// (currentTime jumps back to ~0) counts as progress.
|
|
284
|
+
// - Advance early if a non-looping video ends; bail if frozen too long.
|
|
285
|
+
// Returns true only if real progressing playback was counted.
|
|
253
286
|
async function watchCurrent(page, minSec, maxSec, log) {
|
|
254
287
|
try {
|
|
255
288
|
await page.waitForTimeout(randInt(2500, 4500)); // let the reel viewer mount
|
|
@@ -262,27 +295,39 @@ async function watchCurrent(page, minSec, maxSec, log) {
|
|
|
262
295
|
}).catch(() => false);
|
|
263
296
|
if (!hasVideo) { log('info', '[warmup-fb] no <video> after click — skipping'); return false; }
|
|
264
297
|
|
|
298
|
+
// Skip ads — don't watch, don't count.
|
|
299
|
+
if (await isSponsoredReel(page)) { log('info', '[warmup-fb] sponsored/ad reel — skipping (not counted)'); return false; }
|
|
300
|
+
|
|
265
301
|
const watchMs = randInt(minSec, maxSec) * 1000;
|
|
266
302
|
log('info', `[warmup-fb] watching reel for ~${Math.round(watchMs / 1000)}s (url=${page.url().slice(-28)})`);
|
|
267
303
|
const TICK = 1000;
|
|
268
|
-
let watched = 0
|
|
304
|
+
let watched = 0; // counts ONLY progressing seconds
|
|
305
|
+
let scrolled = false, lastT = -1, frozenTicks = 0, adReChecks = 0;
|
|
269
306
|
while (watched < watchMs) {
|
|
270
307
|
const st = await readVideoState(page);
|
|
271
|
-
//
|
|
272
|
-
if (st && !st.loop) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
if (Math.abs(st.currentTime - lastT) < 0.15) { stallTicks++; if (stallTicks >= 6) { log('info', '[warmup-fb] reel stalled — advancing'); break; } }
|
|
278
|
-
else stallTicks = 0;
|
|
279
|
-
lastT = st.currentTime;
|
|
308
|
+
// Non-looping video finished → go to next.
|
|
309
|
+
if (st && !st.loop && (st.ended || (st.duration > 0 && st.currentTime >= st.duration - 0.6))) {
|
|
310
|
+
log('info', `[warmup-fb] reel ended at ${Math.round(st.currentTime)}s — advancing`);
|
|
311
|
+
break;
|
|
280
312
|
}
|
|
281
|
-
|
|
313
|
+
// Progress = currentTime moved forward, OR wrapped back (loop restart).
|
|
314
|
+
const advanced = !!st && (st.currentTime > lastT + 0.2 || st.currentTime < lastT - 0.5);
|
|
315
|
+
if (advanced) {
|
|
316
|
+
watched += TICK;
|
|
317
|
+
frozenTicks = 0;
|
|
318
|
+
if (!scrolled && watched >= watchMs / 2) { await organicScroll(page, randInt(1, 2)); scrolled = true; }
|
|
319
|
+
} else {
|
|
320
|
+
// Not progressing (frozen / buffering / paused-and-won't-play) — do NOT
|
|
321
|
+
// count this second; bail after ~8s stuck.
|
|
322
|
+
frozenTicks++;
|
|
323
|
+
if (frozenTicks >= 8) { log('info', `[warmup-fb] video frozen ~${frozenTicks}s (counted ${Math.round(watched/1000)}s) — advancing`); break; }
|
|
324
|
+
}
|
|
325
|
+
lastT = st ? st.currentTime : lastT;
|
|
326
|
+
// Re-check sponsored a couple times (a mid-scroll ad reel can swap in).
|
|
327
|
+
if (adReChecks < 2 && watched > 0 && watched % 8000 === 0) { adReChecks++; if (await isSponsoredReel(page)) { log('info', '[warmup-fb] became sponsored mid-watch — advancing'); break; } }
|
|
282
328
|
await page.waitForTimeout(TICK);
|
|
283
|
-
watched += TICK;
|
|
284
329
|
}
|
|
285
|
-
return
|
|
330
|
+
return watched > 0; // only a video with real progressing playback counts
|
|
286
331
|
} catch (e) {
|
|
287
332
|
log('info', `[warmup-fb] watch failed: ${String(e.message || e).slice(0, 90)}`);
|
|
288
333
|
return false;
|