fix browser verification
This commit is contained in:
+115
-115
@@ -1,115 +1,115 @@
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { execSync } from 'child_process';
|
import {execSync} from 'child_process';
|
||||||
|
|
||||||
export function detectBrowser(preferredBrowser = 'auto') {
|
export function detectBrowser(preferredBrowser = 'auto') {
|
||||||
const platform = os.platform();
|
const platform = os.platform();
|
||||||
let browsers = {
|
let browsers = {
|
||||||
'chrome': null,
|
'chrome': null,
|
||||||
'edge': null
|
'edge': null
|
||||||
};
|
};
|
||||||
|
|
||||||
if (platform === 'win32') {
|
if (platform === 'win32') {
|
||||||
browsers.chrome = findWindowsBrowser('Chrome');
|
browsers.chrome = findWindowsBrowser('Chrome');
|
||||||
browsers.edge = findWindowsBrowser('Edge');
|
browsers.edge = findWindowsBrowser('Edge');
|
||||||
} else if (platform === 'darwin') {
|
} else if (platform === 'darwin') {
|
||||||
browsers.chrome = findMacOSBrowser('Google Chrome');
|
browsers.chrome = findMacOSBrowser('Google Chrome');
|
||||||
browsers.edge = findMacOSBrowser('Microsoft Edge');
|
browsers.edge = findMacOSBrowser('Microsoft Edge');
|
||||||
} else if (platform === 'linux') {
|
} else if (platform === 'linux') {
|
||||||
browsers.chrome = findLinuxBrowser('google-chrome');
|
browsers.chrome = findLinuxBrowser('google-chrome');
|
||||||
|
|
||||||
//Arch下AUR安装的chrome为google-chrome-stable
|
//Arch下AUR安装的chrome为google-chrome-stable
|
||||||
if(browsers.chrome == null){
|
if (browsers.chrome == null) {
|
||||||
browsers.chrome = findLinuxBrowser('google-chrome-stable');
|
browsers.chrome = findLinuxBrowser('google-chrome-stable');
|
||||||
}
|
}
|
||||||
|
|
||||||
browsers.edge = findLinuxBrowser('microsoft-edge');
|
browsers.edge = findLinuxBrowser('microsoft-edge');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preferredBrowser === 'auto' || preferredBrowser === undefined) {
|
if (preferredBrowser === 'auto' || preferredBrowser === undefined) {
|
||||||
if (browsers.chrome) {
|
if (browsers.chrome) {
|
||||||
return browsers.chrome;
|
return browsers.chrome;
|
||||||
} else if (browsers.edge) {
|
} else if (browsers.edge) {
|
||||||
return browsers.edge;
|
return browsers.edge;
|
||||||
}
|
}
|
||||||
} else if (browsers[preferredBrowser]) {
|
} else if (browsers[preferredBrowser]) {
|
||||||
console.log(`使用${preferredBrowser === 'chrome' ? 'Chrome' : 'Edge'}浏览器`);
|
console.log(`使用${preferredBrowser === 'chrome' ? 'Chrome' : 'Edge'}浏览器`);
|
||||||
return browsers[preferredBrowser];
|
return browsers[preferredBrowser];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error('未找到Chrome或Edge浏览器,请确保已安装其中之一');
|
console.error('未找到Chrome或Edge浏览器,请确保已安装其中之一');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findWindowsBrowser(browserName) {
|
function findWindowsBrowser(browserName) {
|
||||||
const regKeys = {
|
const regKeys = {
|
||||||
'Chrome': ['chrome.exe', 'Google\\Chrome'],
|
'Chrome': ['chrome.exe', 'Google\\Chrome'],
|
||||||
'Edge': ['msedge.exe', 'Microsoft\\Edge']
|
'Edge': ['msedge.exe', 'Microsoft\\Edge']
|
||||||
};
|
};
|
||||||
const [exeName, folderName] = regKeys[browserName];
|
const [exeName, folderName] = regKeys[browserName];
|
||||||
|
|
||||||
const regQuery = (key) => {
|
const regQuery = (key) => {
|
||||||
try {
|
try {
|
||||||
return execSync(`reg query "${key}" /ve`).toString().trim().split('\r\n').pop().split(' ').pop();
|
return execSync(`reg query "${key}" /ve`).toString().trim().split('\r\n').pop().split(' ').pop();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let browserPath = regQuery(`HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${exeName}`) ||
|
let browserPath = regQuery(`HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${exeName}`) ||
|
||||||
regQuery(`HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${exeName}`);
|
regQuery(`HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${exeName}`);
|
||||||
|
|
||||||
if (browserPath && fs.existsSync(browserPath)) {
|
if (browserPath && fs.existsSync(browserPath)) {
|
||||||
return browserPath;
|
return browserPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const commonPaths = [
|
const commonPaths = [
|
||||||
`C:\\Program Files\\${browserName}\\Application\\${exeName}`,
|
`C:\\Program Files\\${browserName}\\Application\\${exeName}`,
|
||||||
`C:\\Program Files (x86)\\${browserName}\\Application\\${exeName}`,
|
`C:\\Program Files (x86)\\${browserName}\\Application\\${exeName}`,
|
||||||
`C:\\Program Files (x86)\\Microsoft\\${browserName}\\Application\\${exeName}`,
|
`C:\\Program Files (x86)\\Microsoft\\${browserName}\\Application\\${exeName}`,
|
||||||
`${process.env.LOCALAPPDATA}\\${browserName}\\Application\\${exeName}`,
|
`${process.env.LOCALAPPDATA}\\${browserName}\\Application\\${exeName}`,
|
||||||
`${process.env.USERPROFILE}\\AppData\\Local\\${browserName}\\Application\\${exeName}`,
|
`${process.env.USERPROFILE}\\AppData\\Local\\${browserName}\\Application\\${exeName}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
const foundPath = commonPaths.find(path => fs.existsSync(path));
|
const foundPath = commonPaths.find(path => fs.existsSync(path));
|
||||||
if (foundPath) {
|
if (foundPath) {
|
||||||
return foundPath;
|
return foundPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userAppDataPath = process.env.LOCALAPPDATA || `${process.env.USERPROFILE}\\AppData\\Local`;
|
const userAppDataPath = process.env.LOCALAPPDATA || `${process.env.USERPROFILE}\\AppData\\Local`;
|
||||||
const appDataPath = path.join(userAppDataPath, folderName, 'Application');
|
const appDataPath = path.join(userAppDataPath, folderName, 'Application');
|
||||||
|
|
||||||
if (fs.existsSync(appDataPath)) {
|
if (fs.existsSync(appDataPath)) {
|
||||||
const files = fs.readdirSync(appDataPath);
|
const files = fs.readdirSync(appDataPath);
|
||||||
const exePath = files.find(file => file.toLowerCase() === exeName.toLowerCase());
|
const exePath = files.find(file => file.toLowerCase() === exeName.toLowerCase());
|
||||||
if (exePath) {
|
if (exePath) {
|
||||||
return path.join(appDataPath, exePath);
|
return path.join(appDataPath, exePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findMacOSBrowser(browserName) {
|
function findMacOSBrowser(browserName) {
|
||||||
const paths = [
|
const paths = [
|
||||||
`/Applications/${browserName}.app/Contents/MacOS/${browserName}`,
|
`/Applications/${browserName}.app/Contents/MacOS/${browserName}`,
|
||||||
`${os.homedir()}/Applications/${browserName}.app/Contents/MacOS/${browserName}`,
|
`${os.homedir()}/Applications/${browserName}.app/Contents/MacOS/${browserName}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const path of paths) {
|
for (const path of paths) {
|
||||||
if (fs.existsSync(path)) {
|
if (fs.existsSync(path)) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findLinuxBrowser(browserName) {
|
function findLinuxBrowser(browserName) {
|
||||||
try {
|
try {
|
||||||
return execSync(`which ${browserName}`).toString().trim();
|
return execSync(`which ${browserName}`).toString().trim();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
/**
|
||||||
|
* @param {Object} page - Puppeteer
|
||||||
|
* @param {Object} options - 配置选项
|
||||||
|
* @param {number} options.width - 视口宽度
|
||||||
|
* @param {number} options.height - 视口高度
|
||||||
|
* @param {number} options.deviceScaleFactor - 设备缩放因子
|
||||||
|
* @param {boolean} options.isMobile - 模拟移动设备
|
||||||
|
* @param {boolean} options.hasTouch - 支持触摸
|
||||||
|
* @param {boolean} options.isLandscape - 横屏
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function fixBrowserDisplay(page, options = {}) {
|
||||||
|
if (!page) {
|
||||||
|
console.error('页面对象为空,无法修复显示');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
width: 1280,
|
||||||
|
height: 800,
|
||||||
|
deviceScaleFactor: 1,
|
||||||
|
isMobile: false,
|
||||||
|
hasTouch: false,
|
||||||
|
isLandscape: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const settings = {...defaultOptions, ...options};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 设置视口大小和设备比例
|
||||||
|
await page.setViewport({
|
||||||
|
width: settings.width,
|
||||||
|
height: settings.height,
|
||||||
|
deviceScaleFactor: settings.deviceScaleFactor,
|
||||||
|
isMobile: settings.isMobile,
|
||||||
|
hasTouch: settings.hasTouch,
|
||||||
|
isLandscape: settings.isLandscape
|
||||||
|
});
|
||||||
|
|
||||||
|
// 尝试调整窗口大小
|
||||||
|
const session = await page.target().createCDPSession();
|
||||||
|
await session.send('Emulation.setDeviceMetricsOverride', {
|
||||||
|
width: settings.width,
|
||||||
|
height: settings.height,
|
||||||
|
deviceScaleFactor: settings.deviceScaleFactor,
|
||||||
|
mobile: settings.isMobile,
|
||||||
|
screenWidth: settings.width,
|
||||||
|
screenHeight: settings.height
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重置页面缩放
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.body.style.zoom = '100%';
|
||||||
|
document.body.style.transform = 'scale(1)';
|
||||||
|
document.body.style.transformOrigin = '0 0';
|
||||||
|
|
||||||
|
// 尝试修复可能存在的CSS
|
||||||
|
const styleElement = document.createElement('style');
|
||||||
|
styleElement.textContent = `
|
||||||
|
html, body {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
overflow: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container, .main, #app, #root {
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(styleElement);
|
||||||
|
|
||||||
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('修复浏览器显示时出错:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调整CSS比例
|
||||||
|
* @param {Object} page - Puppeteer
|
||||||
|
* @param {number} scale - 缩放比例
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function adjustCssScaling(page, scale = 1) {
|
||||||
|
if (!page) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await page.evaluate((scale) => {
|
||||||
|
const styleElem = document.createElement('style');
|
||||||
|
styleElem.id = 'puppeteer-display-fix';
|
||||||
|
styleElem.textContent = `
|
||||||
|
html {
|
||||||
|
transform: scale(${scale});
|
||||||
|
transform-origin: top left;
|
||||||
|
width: ${100 / scale}% !important;
|
||||||
|
height: ${100 / scale}% !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(styleElem);
|
||||||
|
|
||||||
|
// 重新计算布局
|
||||||
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
}, scale);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('调整CSS比例时出错:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修复高DPI
|
||||||
|
* @param {Object} page - Puppeteer
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function fixHighDpiDisplay(page) {
|
||||||
|
if (!page) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检测设备像素比
|
||||||
|
const devicePixelRatio = await page.evaluate(() => window.devicePixelRatio);
|
||||||
|
|
||||||
|
if (devicePixelRatio > 1) {
|
||||||
|
await page.setViewport({
|
||||||
|
width: 1280,
|
||||||
|
height: 800,
|
||||||
|
deviceScaleFactor: devicePixelRatio
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.evaluate((dpr) => {
|
||||||
|
const meta = document.createElement('meta');
|
||||||
|
meta.setAttribute('name', 'viewport');
|
||||||
|
meta.setAttribute('content', `initial-scale=1, minimum-scale=1, maximum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi, user-scalable=no`);
|
||||||
|
document.head.appendChild(meta);
|
||||||
|
}, devicePixelRatio);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('修复高DPI显示时出错:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完整浏览器显示优化
|
||||||
|
* @param {Object} page - Puppeteer
|
||||||
|
* @param {Object} options - 配置
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function optimizeBrowserDisplay(page, options = {}) {
|
||||||
|
const defaultOptions = {
|
||||||
|
width: 1280,
|
||||||
|
height: 800,
|
||||||
|
deviceScaleFactor: 1,
|
||||||
|
cssScale: null,
|
||||||
|
fixHighDpi: true,
|
||||||
|
forceResize: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = {...defaultOptions, ...options};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 基本显示修复
|
||||||
|
await fixBrowserDisplay(page, {
|
||||||
|
width: config.width,
|
||||||
|
height: config.height,
|
||||||
|
deviceScaleFactor: config.deviceScaleFactor
|
||||||
|
});
|
||||||
|
|
||||||
|
// 修复高DPI显示
|
||||||
|
if (config.fixHighDpi) {
|
||||||
|
await fixHighDpiDisplay(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.cssScale !== null) {
|
||||||
|
await adjustCssScaling(page, config.cssScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果强制调整窗口大小
|
||||||
|
if (config.forceResize && !config.isHeadless) {
|
||||||
|
try {
|
||||||
|
const client = await page.target().createCDPSession();
|
||||||
|
await client.send('Browser.getWindowForTarget');
|
||||||
|
await client.send('Browser.setWindowBounds', {
|
||||||
|
windowId: 1,
|
||||||
|
bounds: {
|
||||||
|
width: config.width,
|
||||||
|
height: config.height
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (resizeError) {
|
||||||
|
// console.log('无法调整窗口大小:', resizeError.message);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await page.evaluate((width, height) => {
|
||||||
|
window.resizeTo(width, height);
|
||||||
|
}, config.width, config.height);
|
||||||
|
} catch (altError) {
|
||||||
|
console.log('失败:', altError.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('浏览器显示优化失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,242 @@
|
|||||||
|
import * as docx from "docx";
|
||||||
|
import cookie from "cookie";
|
||||||
|
import fs from "fs";
|
||||||
|
import {execSync} from "child_process";
|
||||||
|
|
||||||
|
function getGitRevision() {
|
||||||
|
// get git revision and branch
|
||||||
|
try {
|
||||||
|
const revision = execSync("git rev-parse --short HEAD", {stdio: "pipe"}).toString().trim();
|
||||||
|
const branch = execSync("git rev-parse --abbrev-ref HEAD", {stdio: "pipe"}).toString().trim();
|
||||||
|
return {revision, branch};
|
||||||
|
} catch (e) {
|
||||||
|
return {revision: "unknown", branch: "unknown"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建目录
|
||||||
|
function createDirectoryIfNotExists(dirPath) {
|
||||||
|
if (!fs.existsSync(dirPath)) {
|
||||||
|
fs.mkdirSync(dirPath, {recursive: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractCookie(cookies) {
|
||||||
|
let jwtSession = null;
|
||||||
|
let jwtToken = null;
|
||||||
|
let ds = null;
|
||||||
|
let dsr = null;
|
||||||
|
let you_subscription = null;
|
||||||
|
let youpro_subscription = null;
|
||||||
|
|
||||||
|
cookies = cookie.parse(cookies);
|
||||||
|
if (cookies["stytch_session"]) jwtSession = cookies["stytch_session"];
|
||||||
|
if (cookies["stytch_session_jwt"]) jwtToken = cookies["stytch_session_jwt"];
|
||||||
|
if (cookies["DS"]) ds = cookies["DS"];
|
||||||
|
if (cookies["DSR"]) dsr = cookies["DSR"];
|
||||||
|
if (cookies["you_subscription"]) you_subscription = cookies["you_subscription"];
|
||||||
|
if (cookies["youpro_subscription"]) youpro_subscription = cookies["youpro_subscription"];
|
||||||
|
|
||||||
|
return {jwtSession, jwtToken, ds, dsr, you_subscription, youpro_subscription};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionCookie(jwtSession, jwtToken, ds, dsr, you_subscription, youpro_subscription) {
|
||||||
|
let sessionCookie = [];
|
||||||
|
|
||||||
|
// 处理旧版 cookie
|
||||||
|
if (jwtSession && jwtToken) {
|
||||||
|
sessionCookie = [
|
||||||
|
{
|
||||||
|
name: "stytch_session",
|
||||||
|
value: jwtSession,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ydc_stytch_session",
|
||||||
|
value: jwtSession,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "stytch_session_jwt",
|
||||||
|
value: jwtToken,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ydc_stytch_session_jwt",
|
||||||
|
value: jwtToken,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理新版 cookie
|
||||||
|
if (ds) {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "DS",
|
||||||
|
value: ds,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (dsr) {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "DSR",
|
||||||
|
value: dsr,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (you_subscription) {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "you_subscription",
|
||||||
|
value: you_subscription,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (youpro_subscription) {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "youpro_subscription",
|
||||||
|
value: youpro_subscription,
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加隐身模式 cookie(如果启用)
|
||||||
|
if (process.env.INCOGNITO_MODE === "true") {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "incognito",
|
||||||
|
value: "true",
|
||||||
|
domain: "you.com",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
secure: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return sessionCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDocx(content) {
|
||||||
|
let paragraphs = [];
|
||||||
|
content.split("\n").forEach((line) => {
|
||||||
|
paragraphs.push(
|
||||||
|
new docx.Paragraph({
|
||||||
|
children: [new docx.TextRun(line)],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
let doc = new docx.Document({
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
properties: {},
|
||||||
|
children: paragraphs,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return docx.Packer.toBuffer(doc).then((buffer) => buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventStream util
|
||||||
|
function createEvent(event, data) {
|
||||||
|
// if data is object, stringify it
|
||||||
|
if (typeof data === "object") {
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
return `event: ${event}\ndata: ${data}\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractPerplexityCookie(cookieString) {
|
||||||
|
const cookies = cookie.parse(cookieString);
|
||||||
|
return {
|
||||||
|
sessionToken: cookies['__Secure-next-auth.session-token'],
|
||||||
|
isIncognito: cookies['pplx.is-incognito'] === 'true'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPerplexitySessionCookie(extractedCookie) {
|
||||||
|
let sessionCookie = [];
|
||||||
|
|
||||||
|
if (extractedCookie.sessionToken) {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "__Secure-next-auth.session-token",
|
||||||
|
value: extractedCookie.sessionToken,
|
||||||
|
domain: "www.perplexity.ai",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加无痕模式 cookie (如果启用)
|
||||||
|
if (process.env.INCOGNITO_MODE === "true") {
|
||||||
|
sessionCookie.push({
|
||||||
|
name: "pplx.is-incognito",
|
||||||
|
value: "true",
|
||||||
|
domain: "www.perplexity.ai",
|
||||||
|
path: "/",
|
||||||
|
expires: 1800000000,
|
||||||
|
httpOnly: false,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
createEvent,
|
||||||
|
createDirectoryIfNotExists,
|
||||||
|
sleep,
|
||||||
|
extractCookie,
|
||||||
|
getSessionCookie,
|
||||||
|
createDocx,
|
||||||
|
getGitRevision,
|
||||||
|
extractPerplexityCookie,
|
||||||
|
getPerplexitySessionCookie
|
||||||
|
};
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import {exec, execSync} from 'child_process';
|
||||||
|
import {promisify} from 'util';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import os from 'os';
|
||||||
|
import {fileURLToPath} from 'url';
|
||||||
|
import {setupBrowserFingerprint} from './browserFingerprint.mjs';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const execPromise = promisify(exec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} userDataDir - 用户数据目录
|
||||||
|
* @param {string} edgePath - Edge浏览器路径
|
||||||
|
* @param {number} debugPort - 调试端口
|
||||||
|
* @returns {Promise<object>} - browser和page
|
||||||
|
*/
|
||||||
|
export async function launchEdgeBrowser(userDataDir, edgePath, debugPort = 9222) {
|
||||||
|
if (!fs.existsSync(userDataDir)) {
|
||||||
|
fs.mkdirSync(userDataDir, {recursive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭可能的Edge进程
|
||||||
|
try {
|
||||||
|
if (os.platform() === 'win32') {
|
||||||
|
await execPromise('taskkill /f /im msedge.exe').catch(() => {
|
||||||
|
});
|
||||||
|
} else if (os.platform() === 'darwin') {
|
||||||
|
// macOS
|
||||||
|
await execPromise('pkill -f "Microsoft Edge"').catch(() => {
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Linux
|
||||||
|
await execPromise('pkill -f "microsoft-edge"').catch(() => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteDebuggingPort = debugPort;
|
||||||
|
let edgeProcess;
|
||||||
|
|
||||||
|
const args = [
|
||||||
|
`--remote-debugging-port=${remoteDebuggingPort}`,
|
||||||
|
`--user-data-dir="${userDataDir}"`,
|
||||||
|
'--no-first-run',
|
||||||
|
'--no-default-browser-check',
|
||||||
|
'--disable-popup-blocking',
|
||||||
|
'--disable-infobars',
|
||||||
|
'--disable-translate',
|
||||||
|
'--disable-sync',
|
||||||
|
'--window-size=1280,850',
|
||||||
|
'--force-device-scale-factor=1',
|
||||||
|
'about:blank' // 打开空白页
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 启动Edge浏览器
|
||||||
|
const cmdArgs = args.join(' ');
|
||||||
|
const cmd = `"${edgePath}" ${cmdArgs}`;
|
||||||
|
edgeProcess = exec(cmd);
|
||||||
|
|
||||||
|
console.log(`等待Edge浏览器启动...`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
|
||||||
|
const puppeteer = await import('puppeteer-core');
|
||||||
|
|
||||||
|
// 连接到浏览器
|
||||||
|
const browser = await puppeteer.connect({
|
||||||
|
browserURL: `http://127.0.0.1:${remoteDebuggingPort}`,
|
||||||
|
defaultViewport: {width: 1280, height: 850}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取第一个页面
|
||||||
|
const pages = await browser.pages();
|
||||||
|
let page = pages[0];
|
||||||
|
if (!page) {
|
||||||
|
page = await browser.newPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalUserAgent = await page.evaluate(() => navigator.userAgent);
|
||||||
|
// console.log(`Edge浏览器原始用户代理: ${originalUserAgent}`);
|
||||||
|
|
||||||
|
// 应用随机指纹
|
||||||
|
const fingerprint = await setupBrowserFingerprint(page, 'edge');
|
||||||
|
|
||||||
|
// 验证指纹是否成功应用
|
||||||
|
const newUserAgent = await page.evaluate(() => navigator.userAgent);
|
||||||
|
// console.log(`Edge浏览器应用指纹后用户代理: ${newUserAgent}`);
|
||||||
|
|
||||||
|
if (!newUserAgent.includes('Edg')) {
|
||||||
|
console.warn(`警告: 浏览器可能不是Edge。`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
browser,
|
||||||
|
page,
|
||||||
|
process: edgeProcess,
|
||||||
|
fingerprint: fingerprint
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`启动Edge浏览器失败:`, error);
|
||||||
|
|
||||||
|
if (edgeProcess) {
|
||||||
|
try {
|
||||||
|
edgeProcess.kill();
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找Edge浏览器路径
|
||||||
|
* @returns {string|null}
|
||||||
|
*/
|
||||||
|
export function findEdgePath() {
|
||||||
|
const platform = os.platform();
|
||||||
|
|
||||||
|
if (platform === 'win32') {
|
||||||
|
const commonPaths = [
|
||||||
|
`${process.env['ProgramFiles(x86)']}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
||||||
|
`${process.env.ProgramFiles}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
||||||
|
`${process.env.LOCALAPPDATA}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
||||||
|
`C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe`,
|
||||||
|
`C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe`
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const path of commonPaths) {
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (platform === 'darwin') {
|
||||||
|
const macPath = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge';
|
||||||
|
if (fs.existsSync(macPath)) {
|
||||||
|
return macPath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Linux
|
||||||
|
try {
|
||||||
|
const {stdout} = execSync('which microsoft-edge');
|
||||||
|
if (stdout && stdout.trim()) {
|
||||||
|
return stdout.trim();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user