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> = []; logger.info(`Spawning ${config.proxy.count} proxies...`); for (let i = 0; i < config.proxy.count; i++) { logger.debug(`Spawning proxy ${i + 1}...`); 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)); } })()); } 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(); });