2025-04-12 19:38:54 +07:00
|
|
|
import { chromium, type Browser, type LaunchOptions } from "patchright";
|
|
|
|
|
import fs from 'node:fs';
|
|
|
|
|
import * as reflect4 from "./proxy/reflect4";
|
|
|
|
|
import logger from "./logger";
|
|
|
|
|
import Config from "./config";
|
|
|
|
|
|
|
|
|
|
const version = "0.1.0";
|
|
|
|
|
|
|
|
|
|
logger.info(`Castorsrm v${version} - https://github.com/teppyboy/castorsrm`)
|
|
|
|
|
logger.warn("This software is provided by the author as is, without any warranty. Use at your own risk.");
|
|
|
|
|
|
|
|
|
|
let config = new Config();
|
|
|
|
|
if (fs.existsSync("config.json")) {
|
|
|
|
|
logger.info("Reading configuration from 'config.json'...");
|
|
|
|
|
const text = await fs.promises.readFile("config.json", "utf-8");
|
|
|
|
|
config = Config.fromJSON(text);
|
|
|
|
|
} else {
|
|
|
|
|
logger.info("No configuration file found. Using the default configuration.");
|
|
|
|
|
await fs.promises.writeFile("config.json", config.toJSON());
|
|
|
|
|
logger.info("Default configuration file 'config.json' created.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.level = process.env.LOG_LEVEL || config.logger.level;
|
|
|
|
|
logger.info(`Logger level set to '${logger.level}'`);
|
|
|
|
|
|
|
|
|
|
let browser: Browser;
|
|
|
|
|
let launchOptions: LaunchOptions = {
|
|
|
|
|
headless: config.playwright.headless,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.info("Launching browser...");
|
|
|
|
|
logger.debug(`Launch options: ${JSON.stringify(launchOptions)}`);
|
|
|
|
|
|
|
|
|
|
switch (config.playwright.browser) {
|
|
|
|
|
case "chromium":
|
|
|
|
|
logger.info("Using Chromium as the browser provider.");
|
|
|
|
|
logger.warn("Chromium is not supported by Twitch. Use at your own risk.");
|
|
|
|
|
browser = await chromium.launch({ ...launchOptions });
|
|
|
|
|
break;
|
|
|
|
|
case "chrome":
|
|
|
|
|
logger.info("Using Google Chrome as the browser provider.");
|
|
|
|
|
browser = await chromium.launch({ ...launchOptions, channel: "chrome" });
|
|
|
|
|
break;
|
|
|
|
|
case "cdp":
|
|
|
|
|
logger.info("Using Chrome DevTools Protocol (CDP) for browser connection.");
|
|
|
|
|
browser = await chromium.connectOverCDP(config.playwright.cdp);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
logger.warn(`Unsupported browser channel: '${config.playwright.browser}'`);
|
|
|
|
|
logger.warn("Castorsrm will try to launch the browser anyway, but it may not work as expected.");
|
|
|
|
|
browser = await chromium.launch({ ...launchOptions, channel: config.playwright.browser });
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.info("Browser launched successfully, spawning proxies");
|
|
|
|
|
if (config.proxy.mode === "reflect4") {
|
|
|
|
|
const context = await browser.newContext();
|
|
|
|
|
const tasks: Array<Promise<void>> = [];
|
|
|
|
|
logger.info(`Spawning ${config.proxy.count} proxies...`);
|
|
|
|
|
for (let i = 0; i < config.proxy.count; i++) {
|
|
|
|
|
logger.debug(`Spawning proxy ${i + 1}...`);
|
2025-04-12 21:58:19 +07:00
|
|
|
tasks.push((async () => {
|
|
|
|
|
const spawnId = `${i + 1}`;
|
|
|
|
|
while (true) {
|
|
|
|
|
try {
|
|
|
|
|
await reflect4.spawn(context, config.playwright.url, spawnId);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(`[${spawnId}] Error while running: ${e}`);
|
|
|
|
|
}
|
|
|
|
|
logger.warn(`[${spawnId}] Restarting in 3 seconds...`);
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 3 * 1000));
|
|
|
|
|
}
|
|
|
|
|
})());
|
2025-04-12 19:38:54 +07:00
|
|
|
}
|
|
|
|
|
await Promise.all(tasks);
|
|
|
|
|
logger.info("All proxies spawned successfully.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
process.on("SIGINT", async () => {
|
|
|
|
|
logger.info("Received SIGINT. Closing browser...");
|
|
|
|
|
for (const context of browser.contexts()) {
|
|
|
|
|
await context.close();
|
|
|
|
|
}
|
|
|
|
|
await browser.close();
|
|
|
|
|
process.exit();
|
|
|
|
|
});
|