This commit is contained in:
NAME
2026-05-13 11:49:16 +00:00
parent a7ba436169
commit 31129e23f6
4 changed files with 70 additions and 46 deletions
+4 -3
View File
@@ -1,12 +1,12 @@
// sqs.module.ts
import { Module, Global } from '@nestjs/common';
import { SqsService } from './sqs.service';
import {Global, Module} from '@nestjs/common';
import {SqsService} from './sqs.service';
import {SqsPostService} from "./sqs.post.service";
import {SqsPosterWorker} from "./sqs.poster.worker";
import {XPosterRouterService} from "../x-poster/x-poster.router.service";
import {XPosterModule} from "../x-poster/x-poster.module";
import {FacebookApi} from "../x-poster/facebook.api";
import {NotifyService} from "../notify.service";
import {XCacheService} from "../x-cache/x-cache.service";
@Global()
@Module({
@@ -17,6 +17,7 @@ import {NotifyService} from "../notify.service";
SqsPosterWorker,
FacebookApi,
NotifyService,
XCacheService,
],
exports: [SqsService],
})
+5
View File
@@ -5,6 +5,7 @@ import {SUPPORT_SOCIAL_PROVIDERS, XPosterRouterService, XStrategy} from "../x-po
import {rand} from "../helper";
import {FacebookApi} from "../x-poster/facebook.api";
import {NotifyService} from "../notify.service";
import {XCacheService} from "../x-cache/x-cache.service";
@Injectable()
export class SqsPosterWorker {
@@ -15,6 +16,7 @@ export class SqsPosterWorker {
private readonly xRouterService: XPosterRouterService,
private readonly facebookApi: FacebookApi,
private readonly notifyService: NotifyService,
private readonly xCacheService: XCacheService,
) {
}
@@ -23,11 +25,14 @@ export class SqsPosterWorker {
await this.notifyService.sendMessageToTele(`🚀 Worker started for ${await this.sqs.getQueueName()}`)
//check cookie
if (!await this.xCacheService.isXCookiesAlive()) {
this.xRouterService.verifyCookie().catch((err) => {
console.error(`SqsPosterWorker_verifyCookie`);
console.error(err);
});
}
let ReceiptHandle = '';
while (true) {
try {
+51 -33
View File
@@ -3,6 +3,8 @@ import {HttpException, Injectable, Logger, OnModuleDestroy, OnModuleInit,} from
import {Browser, BrowserContext, chromium, Page} from 'playwright';
import {rand} from "../helper";
import {getAccount} from "./utils/x-headers.util";
import {XCacheService} from "../x-cache/x-cache.service";
import {NotifyService} from "../notify.service";
export interface BrowserAccount {
accountId: string;
@@ -35,6 +37,12 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
private readonly MAX_CONTEXTS = 5;
private readonly CONTEXT_TTL_MS = 15 * 60 * 1000; // 15 phút
constructor(
private readonly xCacheService: XCacheService,
private readonly notifyService: NotifyService,
) {
}
async onModuleInit() {
// Lazy launch chỉ mở khi cần
setInterval(() => this.cleanupStaleContexts(), 60_000);
@@ -141,7 +149,7 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
return ctx.newPage();
}
async verifyCookie() {
async verifyCookie(sendNotiWhenAlive = false): Promise<boolean> {
const page = await this.newPage();
try {
@@ -151,15 +159,25 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
});
await page.waitForTimeout(2000 + (Math.random() + Math.random()) * 3000);
await page.mouse.wheel(0, rand(300, 500));
// Detect login/challenge screen
return await this.isCookieLive(page, sendNotiWhenAlive);
} catch (er) {
this.logger.error(`Browser verify cookie fail: ${er.message}`);
return false;
} finally {
await page?.close().catch(() => null);
}
}
async isCookieLive(page: Page, sendNotiWhenAlive = false): Promise<boolean> {
this.logger.debug('isCookieLive?');
if (page.url().includes('/home')) {
this.logger.log('Cookies live');
await this.xCacheService.setStateXCookiesIsSillALive();
if (sendNotiWhenAlive) {
await this.notifyService.sendMessageToTele('✅Verify cookie pass')
}
return true;
// return {
// success: false,
// error: 'Redirected to login',
// needsRelogin: true,
// };
}
const isLoggedIn = await page
.locator('[data-testid="SideNav_AccountSwitcher_Button"], [data-testid="AppTabBar_Home_Link"]')
@@ -168,16 +186,32 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
.catch(() => false);
this.logger.log(`🔐 Session restore: ${isLoggedIn ? 'LOGGED IN' : 'GUEST (cookie có thể expired)'}`);
// await page.close();
if (isLoggedIn) {
await this.xCacheService.setStateXCookiesIsSillALive();
if (sendNotiWhenAlive) {
await this.notifyService.sendMessageToTele('✅Verify cookie pass')
}
} else {
await this.xCacheService.setStateXCookiesIsDie();
await this.notifyService.sendUrgentMessageToTele('❌Cookie đã hết hạn vui lòng cập nhập để sử dụng.')
}
return isLoggedIn;
} catch (er) {
this.logger.error(`Browser verify cookie fail: ${er.message}`);
return false;
} finally {
await page?.close().catch(() => null);
}
}
// async actVerifyCookie(): Promise<any> {
// this.logger.debug('==> actVerifyCookie');
// // const isAlive = await this.cookieSvc.verifyCookie();
// const isAlive = await this.verifyCookie();
// if (!isAlive) {
// await this.xCacheService.setStateXCookiesIsDie();
// await this.notifyService.sendUrgentMessageToTele('❌Cookie đã hết hạn vui lòng cập nhập để sử dụng.')
// }
// await this.xCacheService.setStateXCookiesIsSillALive();
// await this.notifyService.sendMessageToTele('✅Verify cookie pass')
//
// return isAlive;
// }
async likeTweet(tweetUrl: string) {
let page: Page | null = null;
@@ -285,12 +319,7 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
};
}
const isLoggedIn = await page
.locator('[data-testid="SideNav_AccountSwitcher_Button"], [data-testid="AppTabBar_Home_Link"]')
.first()
.isVisible()
.catch(() => false);
this.logger.debug(`postTweet: ${isLoggedIn ? 'LOGGED IN' : 'LOGGED OUT'}`);
await this.isCookieLive(page, false);
await page.mouse.wheel(200, rand(300, 800));
await page.waitForTimeout(rand(2000, 5000));
@@ -364,13 +393,7 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
await page.waitForTimeout(rand(2000, 4000));
const isLoggedIn = await page
.locator('[data-testid="SideNav_AccountSwitcher_Button"], [data-testid="AppTabBar_Home_Link"]')
.first()
.isVisible()
.catch(() => false);
this.logger.debug(`postQuote: ${isLoggedIn ? 'LOGGED IN' : 'LOGGED OUT'}`);
await this.isCookieLive(page, false);
// ===== CHECK LOGIN =====
if (await page.locator('input[name="text"]').count()) {
@@ -520,12 +543,7 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
this.logger.debug(`đợi UI ổn...`)
await page.waitForSelector('article', {timeout: 7000});
const isLoggedIn = await page
.locator('[data-testid="SideNav_AccountSwitcher_Button"], [data-testid="AppTabBar_Home_Link"]')
.first()
.isVisible()
.catch(() => false);
this.logger.debug(`postReply: ${isLoggedIn ? 'LOGGED IN' : 'LOGGED OUT'}`);
await this.isCookieLive(page, false);
// scroll nhẹ
this.logger.debug(`scroll nhẹ ...`)
+1 -1
View File
@@ -93,8 +93,8 @@ export class XPosterRouterService {
if (['cookie', 'browser'].includes(method)) {
if (!canUseCookie) {
await this.notifyService.sendUrgentMessageToTele('❌ Vui lòng cập nhập cookie để sử dụng ');
this.logger.error('Cookie đã hết hạn, vui lòng cập nhập');
await this.notifyService.sendUrgentMessageToTele('❌ Vui lòng cập nhập cookie để sử dụng ');
continue;
}
}